diff --git a/src/nt.cpp b/src/nt.cpp index b5adc68..0a3b247 100644 --- a/src/nt.cpp +++ b/src/nt.cpp @@ -12,64 +12,70 @@ namespace nt { TypeDef NTScalar::build() { - TypeDef def(TypeCode::Struct, - value.isarray() ? "epics:nt/NTScalarArray:1.0" : "epics:nt/NTScalar:1.0"); + return TypeDef(TypeCode::Struct, + value.isarray() ? "epics:nt/NTScalarArray:1.0" : "epics:nt/NTScalar:1.0", { + Member(value, "value"), + Member(TypeCode::Struct, "alarm", "alarm_t", { + Member(TypeCode::Int32, "severity"), + Member(TypeCode::Int32, "status"), + Member(TypeCode::String, "message"), + }), + Member(TypeCode::Struct, "timeStamp", "time_t", { + Member(TypeCode::Int64, "secondsPastEpoch"), + Member(TypeCode::Int32, "nanoseconds"), + Member(TypeCode::Int32, "userTag"), + }), + }); - const bool isnumeric = value.kind()==Kind::Integer || value.kind()==Kind::Real; - const auto scalar = value.scalarOf(); +// const bool isnumeric = value.kind()==Kind::Integer || value.kind()==Kind::Real; +// const auto scalar = value.scalarOf(); - def.begin() - .insert("value", value) - .insert("alarm", "alarm_t", TypeCode::Struct).seek("alarm") - .insert("severity", TypeCode::Int32) - .insert("status", TypeCode::Int32) - .insert("message", TypeCode::String) - .up() - .insert("timeStamp", "time_t", TypeCode::Struct).seek("timeStamp") - .insert("secondsPastEpoch", TypeCode::Int64) - .insert("nanoseconds", TypeCode::Int32) - .insert("userTag", TypeCode::Int32) - .up() - ; +// if(display && isnumeric) { +// def.begin() +// .insert("display", TypeCode::Struct).seek("display") +// .insert("limitLow", scalar) +// .insert("limitHigh", scalar) +// .insert("description", TypeCode::String) +// //.insert("format", TypeCode::String) +// .insert("units", TypeCode::String) +// .up() +// ; +// } - if(display && isnumeric) { - def.begin() - .insert("display", TypeCode::Struct).seek("display") - .insert("limitLow", scalar) - .insert("limitHigh", scalar) - .insert("description", TypeCode::String) - //.insert("format", TypeCode::String) - .insert("units", TypeCode::String) - .up() - ; - } +// if(control && isnumeric) { +// def.begin() +// .insert("control", TypeCode::Struct).seek("control") +// .insert("limitLow", scalar) +// .insert("limitHigh", scalar) +// .insert("minStep", scalar) +// .up() +// ; +// } - if(control && isnumeric) { - def.begin() - .insert("control", TypeCode::Struct).seek("control") - .insert("limitLow", scalar) - .insert("limitHigh", scalar) - .insert("minStep", scalar) - .up() - ; - } +// if(valueAlarm && isnumeric) { +// def.begin() +// .insert("valueAlarm", TypeCode::Struct).seek("valueAlarm") +// .insert("active", TypeCode::Bool) // useless? +// .insert("lowAlarmLimit", scalar) +// .insert("lowWarningLimit", scalar) +// .insert("highWarningLimit", scalar) +// .insert("highAlarmLimit", scalar) +// .insert("lowAlarmSeverity", TypeCode::Int32) +// .insert("lowWarningSeverity", TypeCode::Int32) +// .insert("highWarningSeverity", TypeCode::Int32) +// .insert("highAlarmSeverity", TypeCode::Int32) +// .insert("hysteresis", TypeCode::Float64) +// .up() +// ; +// } + +// return def; +} + +TypeDef NTNDArray::build() +{ + TypeDef def(TypeCode::Struct, "epics:nt/NTNDArray:1.0"); - if(valueAlarm && isnumeric) { - def.begin() - .insert("valueAlarm", TypeCode::Struct).seek("valueAlarm") - .insert("active", TypeCode::Bool) // useless? - .insert("lowAlarmLimit", scalar) - .insert("lowWarningLimit", scalar) - .insert("highWarningLimit", scalar) - .insert("highAlarmLimit", scalar) - .insert("lowAlarmSeverity", TypeCode::Int32) - .insert("lowWarningSeverity", TypeCode::Int32) - .insert("highWarningSeverity", TypeCode::Int32) - .insert("highAlarmSeverity", TypeCode::Int32) - .insert("hysteresis", TypeCode::Float64) - .up() - ; - } return def; } diff --git a/src/pvxs/data.h b/src/pvxs/data.h index 232d2e6..562b980 100644 --- a/src/pvxs/data.h +++ b/src/pvxs/data.h @@ -6,6 +6,7 @@ #ifndef PVXS_DATA_H #define PVXS_DATA_H +#include #include #include #include @@ -162,53 +163,48 @@ inline std::ostream& operator<<(std::ostream& strm, TypeCode c) { return strm; } +struct Member { + TypeCode code; + std::string name; + std::string id; + std::vector children; + + Member(TypeCode code, const std::string& name, const std::string& id = std::string()) + :Member(code, name, 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, std::initializer_list children) + :Member(code, name , std::string(), children) + {} +}; + class PVXS_API TypeDef { public: struct Node; private: - struct NodeDeletor { - PVXS_API void operator()(Node *p); - }; - std::unique_ptr root; + std::shared_ptr top; public: TypeDef() = default; - TypeDef(TypeCode code, const char *id=nullptr); - // moveable, not copyable - TypeDef(const TypeDef&) = delete; + // moveable, copyable + TypeDef(const TypeDef&) = default; TypeDef(TypeDef&&) = default; - TypeDef& operator=(const TypeDef&) = delete; + TypeDef& operator=(const TypeDef&) = default; TypeDef& operator=(TypeDef&&) = default; explicit TypeDef(const Value&); ~TypeDef(); - TypeDef clone() const; + TypeDef(TypeCode code, const std::string& id, std::initializer_list children); + TypeDef(TypeCode code, const std::string& id=std::string()) + :TypeDef(code, id, {}) + {} + TypeDef(TypeCode code, std::initializer_list children) + :TypeDef(code, std::string(), children) + {} - class PVXS_API Cursor { - friend class TypeDef; - TypeDef* owner; - Node* parent; - size_t index; // [0, parent->children.size()] (index==size() appends) - public: + //TypeDef& operator+=(const Member& ) - Cursor& seek(const char *name); - Cursor& change(const char *id, TypeCode code); - - Cursor& insert(const char *name, const char *id, TypeCode code); - inline Cursor& insert(const char *name, TypeCode code) { - return insert(name, nullptr, code); - } - - Cursor& add(const char *name, const TypeDef& def); - Cursor& up(); - Cursor& reset(); - TypeDef& end() { return *owner; } - //! shorthand for .end().create() - inline Value create(); - }; - friend class Cursor; - - Cursor begin(); Value create() const; friend @@ -372,10 +368,6 @@ public: PVXS_API std::ostream& operator<<(std::ostream& strm, const Value& val); -Value TypeDef::Cursor::create() { - return end().create(); -} - } // namespace pvxs #endif // PVXS_DATA_H diff --git a/src/pvxs/nt.h b/src/pvxs/nt.h index 6e9d07d..164357b 100644 --- a/src/pvxs/nt.h +++ b/src/pvxs/nt.h @@ -22,6 +22,11 @@ struct NTScalar { TypeDef build(); }; +struct NTNDArray { + PVXS_API + TypeDef build(); +}; + }} // namespace pvxs::nt #endif // PVXS_NT_H diff --git a/src/type.cpp b/src/type.cpp index e19f3f3..eac0791 100644 --- a/src/type.cpp +++ b/src/type.cpp @@ -85,33 +85,10 @@ const char* TypeCode::name() const return "\?\?\?_t"; } -struct TypeDef::Node { - Node * const parent; - std::string id; - TypeCode code; - std::vector> children; - explicit Node(Node *parent) :parent(parent) {} - Node(Node* parent, const char *id, TypeCode code) :parent(parent), id(id?id:""), code(code) {} - - decltype (TypeDef::root) clone(Node *new_parent) const { - decltype (TypeDef::root) ret{new Node(new_parent, id.c_str(), code)}; - ret->children.reserve(children.size()); - for(auto& pair : children) { - ret->children.emplace_back(pair.first, pair.second->clone(ret.get())); - } - return ret; - } -}; - -void TypeDef::NodeDeletor::operator()(Node *p) -{ - delete p; -} - static -void node_validate(const TypeDef::Node* parent, const char *id, TypeCode code) +void node_validate(const Member* parent, const std::string& id, TypeCode code) { - if(id && code!=TypeCode::Struct && code!=TypeCode::Union) + if(!id.empty() && code!=TypeCode::Struct && code!=TypeCode::Union) throw std::runtime_error("Only Struct or Union may have an ID"); if(parent) { auto c = parent->code.scalarOf(); @@ -144,56 +121,50 @@ void name_validate(const char *name) } } -TypeDef::TypeDef(TypeCode code, const char *id) - :root{new Node(nullptr, id, code)} +Member::Member(TypeCode code, const std::string& name, const std::string& id, std::initializer_list children) + :code(code), name(name), id(id) { - node_validate(nullptr, id, code); + if(!name.empty()) + name_validate(name.c_str()); + for(auto& child : children) { + node_validate(this, child.id, child.code); + this->children.push_back(child); + } +} + +TypeDef::TypeDef(TypeCode code, const std::string& id, std::initializer_list children) +{ + decltype (top) temp(new Member(code, "", id, children)); + top = std::move(temp); } static -void copy_tree(const FieldDesc* desc, TypeDef::Node& node) +void copy_tree(const FieldDesc* desc, Member& node) { node.code = desc->code; node.id = desc->id; node.children.reserve(desc->miter.size()); for(auto& pair : desc->miter) { - node.children.emplace_back(pair.first, - decltype (node.children)::value_type::second_type{new TypeDef::Node(&node)}); - copy_tree(desc+pair.second, *node.children.back().second); + auto cdesc = desc+pair.second; + node.children.emplace_back(cdesc->code, cdesc->id, pair.first); + copy_tree(cdesc, node.children.back()); } } TypeDef::TypeDef(const Value& o) { if(o.desc) { - root.reset(new Node(nullptr)); + std::shared_ptr root(new Member(o.desc->code, o.desc->id)); + copy_tree(o.desc, *root); + top = std::move(root); } } TypeDef::~TypeDef() {} -TypeDef TypeDef::clone() const -{ - TypeDef ret; - if(root) { - ret.root = root->clone(nullptr); - } - return ret; -} - -TypeDef::Cursor TypeDef::begin() -{ - if(!root) - throw std::runtime_error("Can't edit empty TypeDef"); - Cursor ret; - ret.owner = this; - ret.reset(); - return ret; -} - static -void build_tree(std::vector& desc, const TypeDef::Node& node) +void build_tree(std::vector& desc, const Member& node) { auto code = node.code; if(node.code==TypeCode::StructA || node.code==TypeCode::UnionA) { @@ -217,20 +188,20 @@ void build_tree(std::vector& desc, const TypeDef::Node& node) } - for(auto& pair : node.children) { + for(auto& cnode : node.children) { const auto cindex = desc.size(); - build_tree(desc, *pair.second); // recurse. may realloc desc + build_tree(desc, cnode); // recurse. may realloc desc auto& fld = desc[index]; auto& child = desc[cindex]; - fld.hash ^= std::hash{}(pair.first) ^ child.hash; + fld.hash ^= std::hash{}(cnode.name) ^ child.hash; - fld.mlookup[pair.first] = cindex-index; - fld.miter.emplace_back(pair.first, cindex-index); + fld.mlookup[cnode.name] = cindex-index; + fld.miter.emplace_back(cnode.name, cindex-index); - std::string cname = pair.first+"."; + std::string cname = cnode.name+"."; if(fld.code.code==TypeCode::Struct && fld.code==child.code) { // propagate names from sub-struct for(auto& cpair : child.mlookup) { @@ -249,124 +220,28 @@ void build_tree(std::vector& desc, const TypeDef::Node& node) Value TypeDef::create() const { - if(!root) + if(!top) throw std::logic_error("Empty TypeDef"); auto desc = std::make_shared>(); - build_tree(*desc, *root); + build_tree(*desc, *top); FieldDesc_calculate_offset(desc->data()); std::shared_ptr type(desc, desc->data()); // alias return Value(type); } -TypeDef::Cursor& TypeDef::Cursor::seek(const char *name) -{ - while(name && name[0]) { - auto sep = strchr(name, '.'); - std::string fname; - if(sep) { - fname = std::string(name, sep-name); - name = sep+1; - } else { - fname = name; - name = nullptr; - } - - for(auto i : range(parent->children.size())) { - auto& pair = parent->children[i]; - if(pair.first==fname) { - auto code = pair.second->code.scalarOf(); - if(code==TypeCode::Union || code==TypeCode::Struct) { - parent = pair.second.get(); - index = parent->children.size(); - - } else if(sep) { - throw std::runtime_error("Can only seek through Struct/Union"); - - } else { - index = i; - } - } - } - } - - return *this; -} - -TypeDef::Cursor& TypeDef::Cursor::change(const char *id, TypeCode code) -{ - node_validate(parent, id, code); - - if(index>=parent->children.size()) { - throw std::runtime_error("Cursor does not select a field"); - } else { - auto& fld = parent->children[index]; - if(code.kind()!=Kind::Compound && !fld.second->children.empty()) - throw std::runtime_error("May not change type of Compound field w/ sub-fields"); - fld.second->id = id; - fld.second->code = code; - } - return *this; -} - -TypeDef::Cursor& TypeDef::Cursor::insert(const char *name, const char *id, TypeCode code) -{ - node_validate(parent, id, code); - name_validate(name); - - decltype (owner->root) node{new Node(parent, id, code)}; - - parent->children.emplace(parent->children.begin()+index, - name, std::move(node)); - index++; - return *this; -} - -TypeDef::Cursor& TypeDef::Cursor::add(const char *name, const TypeDef& def) -{ - name_validate(name); - - if(!def.root) - throw std::runtime_error("Empty TypeDef"); - - node_validate(parent, def.root->id.c_str(), def.root->code); - - parent->children.emplace(parent->children.begin()+index, - name, std::move(def.root->clone(parent))); - - return *this; -} - -TypeDef::Cursor& TypeDef::Cursor::up() -{ - if(parent!=owner->root.get()) { - parent = parent->parent; - index = parent->children.size(); - } else { - throw std::logic_error("Can't go up() from root"); - } - return *this; -} - -TypeDef::Cursor& TypeDef::Cursor::reset() -{ - parent = owner->root.get(); - index = parent->children.size(); - return *this; -} - static -void show_Node(std::ostream& strm, const std::string& name, const TypeDef::Node* node, unsigned level=0) +void show_Node(std::ostream& strm, const std::string& name, const Member* node, unsigned level=0) { strm<code; if(!node->id.empty()) strm<<" \""<id<<"\""; if(!node->children.empty()) { strm<<" {\n"; - for(auto& pair : node->children) { + for(auto& cnode : node->children) { indent(strm, level+1); - show_Node(strm, pair.first, pair.second.get(), level+1); + show_Node(strm, cnode.name, &cnode, level+1); } indent(strm, level); strm.put('}'); @@ -382,10 +257,10 @@ void show_Node(std::ostream& strm, const std::string& name, const TypeDef::Node* std::ostream& operator<<(std::ostream& strm, const TypeDef& def) { - if(!def.root) { + if(!def.top) { strm<<"\n"; } else { - show_Node(strm, std::string(), def.root.get()); + show_Node(strm, std::string(), def.top.get()); } return strm; } diff --git a/test/testtype.cpp b/test/testtype.cpp index 16dd37b..636d120 100644 --- a/test/testtype.cpp +++ b/test/testtype.cpp @@ -31,10 +31,9 @@ void testBasic() { testDiag("%s()", __func__); - auto top = TypeDef(TypeCode::Struct, "simple_t") - .begin() - .insert("value", nullptr, TypeCode::Float64) - .create(); + auto top = TypeDef(TypeCode::Struct, "simple_t", { + Member(TypeCode::Float64, "value"), + }).create(); testOk1(top.valid()); testEq(top.type(), TypeCode::Struct); @@ -74,33 +73,29 @@ void testTypeDef() testEq(std::string(SB()< arr(3); arr[0] = TypeDef(TypeCode::UInt32).create(); - arr[1] = TypeDef(TypeCode::Struct) - .begin() - .insert("q", TypeCode::String) - .create(); + arr[1] = TypeDef(TypeCode::Struct, {Member(TypeCode::String, "q")}).create(); // leave [2] as null arr[0] = 123;