From 50963f0a3e56327ab4f231b0a430ff54ffae64bb Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 11 Dec 2019 09:11:52 -0800 Subject: [PATCH] reorg to separate type handling --- src/Makefile | 1 + src/data.cpp | 460 ----------------------------------------------- src/dataimpl.h | 10 -- src/type.cpp | 474 +++++++++++++++++++++++++++++++++++++++++++++++++ src/util.cpp | 8 + src/utilpvt.h | 1 + 6 files changed, 484 insertions(+), 470 deletions(-) create mode 100644 src/type.cpp diff --git a/src/Makefile b/src/Makefile index eedc4df..796567c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -49,6 +49,7 @@ LIB_SRCS += log.cpp LIB_SRCS += unittest.cpp LIB_SRCS += util.cpp LIB_SRCS += bitmask.cpp +LIB_SRCS += type.cpp LIB_SRCS += data.cpp LIB_SRCS += dataencode.cpp LIB_SRCS += evhelper.cpp diff --git a/src/data.cpp b/src/data.cpp index 5e4f6f8..db27b4f 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -14,390 +14,6 @@ namespace pvxs { -bool TypeCode::valid() const -{ - if((code&0x10) && code!=Null) - return false; // fixed size not supported - switch(scalarOf().code) { -#define CASE(CASE, LBL) case CASE: - CASE(Bool, "bool"); - CASE(Int8, "int8_t"); - CASE(Int16, "int16_t"); - CASE(Int32, "int32_t"); - CASE(Int64, "int64_t"); - CASE(UInt8, "uint8_t"); - CASE(UInt16, "uint16_t"); - CASE(UInt32, "uint32_t"); - CASE(UInt64, "uint64_t"); - CASE(Float32,"float"); - CASE(Float64,"double"); - CASE(String, "string"); - CASE(Any, "any"); - CASE(Union, "union"); - CASE(Struct, "struct"); - CASE(Null, "null"); -#undef CASE - return true; - default: - return false; - } -} - -const char* TypeCode::name() const -{ - switch(code) { -#define CASE(CASE, LBL) case TypeCode::CASE: return LBL - CASE(Bool, "bool"); - CASE(Int8, "int8_t"); - CASE(Int16, "int16_t"); - CASE(Int32, "int32_t"); - CASE(Int64, "int64_t"); - CASE(UInt8, "uint8_t"); - CASE(UInt16, "uint16_t"); - CASE(UInt32, "uint32_t"); - CASE(UInt64, "uint64_t"); - CASE(Float32,"float"); - CASE(Float64,"double"); - CASE(String, "string"); - CASE(Any, "any"); - CASE(Union, "union"); - CASE(Struct, "struct"); - CASE(Null, "null"); -#undef CASE -#define CASE(CASE, LBL) case TypeCode::CASE##A: return LBL "[]" - CASE(Bool, "bool"); - CASE(Int8, "int8_t"); - CASE(Int16, "int16_t"); - CASE(Int32, "int32_t"); - CASE(Int64, "int64_t"); - CASE(UInt8, "uint8_t"); - CASE(UInt16, "uint16_t"); - CASE(UInt32, "uint32_t"); - CASE(UInt64, "uint64_t"); - CASE(Float32,"float"); - CASE(Float64,"double"); - CASE(String, "string"); - CASE(Any, "any"); - CASE(Union, "union"); - CASE(Struct, "struct"); -#undef CASE - } - 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) -{ - if(id && 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(); - if(c!=TypeCode::Struct && c!=TypeCode::Union) - throw std::runtime_error("Only (array of) Struct or Union may have members"); - } -} - -static -void name_validate(const char *name) -{ - // [a-zA-Z_][a-zA-Z0-9_]* - - if(!name || name[0]=='\0') - throw std::runtime_error("empty field name not allowed"); - for(size_t i=0; name[i]; i++) { - char c = name[i]; - if(c>='0' && c<='9' && i>0) { - // number ok after first - } else if((c>='a' && c<='z') || (c>='A' && c<='Z')) { - // alphas ok - } else { - switch(c) { - case '_': - break; - default: - throw std::runtime_error(SB()<<"invalid field name \""<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); - } -} - -TypeDef::TypeDef(const Value& o) -{ - if(o.desc) { - root.reset(new Node(nullptr)); - copy_tree(o.desc, *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) -{ - auto code = node.code; - if(node.code==TypeCode::StructA || node.code==TypeCode::UnionA) { - - desc.emplace_back(); - auto& fld = desc.back(); - fld.code = node.code; - // struct/union array have no ID - fld.hash = node.code.code; - code = code.scalarOf(); - } - - const auto index = desc.size(); - desc.emplace_back(); - - { - auto& fld = desc.back(); - fld.code = code; - fld.id = node.id; - fld.hash = code.code ^ std::hash{}(fld.id); - } - - - for(auto& pair : node.children) { - const auto cindex = desc.size(); - - build_tree(desc, *pair.second); // recurse. may realloc desc - - auto& fld = desc[index]; - auto& child = desc[cindex]; - - fld.hash ^= std::hash{}(pair.first) ^ child.hash; - - fld.mlookup[pair.first] = cindex-index; - fld.miter.emplace_back(pair.first, cindex-index); - - std::string cname = pair.first+"."; - if(fld.code.code==TypeCode::Struct && fld.code==child.code) { - // propagate names from sub-struct - for(auto& cpair : child.mlookup) { - fld.mlookup[cname+cpair.first] = cindex-index+cpair.second; - } - } - } - - desc[index].num_index = desc.size()-index; - - if(node.code==TypeCode::StructA || node.code==TypeCode::UnionA) - { - desc[index-1].num_index = desc.size()-index+1; - } -} - -Value TypeDef::create() const -{ - if(!root) - throw std::logic_error("Empty TypeDef"); - - auto desc = std::make_shared>(); - build_tree(*desc, *root); - 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 indent(std::ostream& strm, unsigned level) { - for(auto i : range(level)) { - (void)i; - strm<<" "; - } -} - -static -void show_Node(std::ostream& strm, const std::string& name, const TypeDef::Node* node, unsigned level=0) -{ - strm<code; - if(!node->id.empty()) - strm<<" \""<id<<"\""; - if(!node->children.empty()) { - strm<<" {\n"; - for(auto& pair : node->children) { - indent(strm, level+1); - show_Node(strm, pair.first, pair.second.get(), level+1); - } - indent(strm, level); - strm.put('}'); - if(!name.empty()) - strm<<" "<\n"; - } else { - show_Node(strm, std::string(), def.root.get()); - } - return strm; -} - NoConvert::NoConvert() :std::runtime_error ("No conversion defined") {} @@ -960,80 +576,4 @@ size_t FieldStorage::index() const return ret; } -void FieldDesc_calculate_offset(FieldDesc* const top) -{ - top->offset = 0; - uint16_t offset = 1; - size_t index = 1; - while(index < top->size()) { - auto& fld = top[index]; - - switch (fld.code.code) { - case TypeCode::Struct: - if(top->code==fld.code) { - // sub-structure - fld.offset = offset++; - index++; - } else { - // structure inside union or array of struct - // new offset zero - FieldDesc_calculate_offset(top); - index+=top->size(); - } - break; - case TypeCode::Union: - // number in parent structure/union - fld.offset = offset++; - // new offset zero for each child - for(auto& pair : fld.miter) { - FieldDesc_calculate_offset(top+index+pair.second); - } - index += fld.size(); - break; - case TypeCode::StructA: - case TypeCode::UnionA: - // number in parent structure/union - fld.offset = offset++; - index++; - // new offset zero for child - FieldDesc_calculate_offset(top+index); - index += top[index].size(); - break; - default: - fld.offset = offset++; - index++; - break; - } - fld.next_offset = offset; - } - top->next_offset = offset; -} - -std::ostream& operator<<(std::ostream& strm, const FieldDesc* desc) -{ - for(auto idx : range(desc->size())) { - auto& fld = desc[idx]; - strm<<"["<" - " ["< "< - FieldDesc* operator[](T key) { - auto it = mlookup.find(key); - if(it!=mlookup.end()) { - return this+it.second; - } else { - return nullptr; - } - } - // number of FieldDesc nodes which describe this node. Inclusive. always size()>=1 inline size_t size() const { return num_index; } }; diff --git a/src/type.cpp b/src/type.cpp new file mode 100644 index 0000000..e19f3f3 --- /dev/null +++ b/src/type.cpp @@ -0,0 +1,474 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * pvxs is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + +#include +#include + +#include + +#include "dataimpl.h" +#include "utilpvt.h" + +namespace pvxs { + +bool TypeCode::valid() const +{ + if((code&0x10) && code!=Null) + return false; // fixed size not supported + switch(scalarOf().code) { +#define CASE(CASE, LBL) case CASE: + CASE(Bool, "bool"); + CASE(Int8, "int8_t"); + CASE(Int16, "int16_t"); + CASE(Int32, "int32_t"); + CASE(Int64, "int64_t"); + CASE(UInt8, "uint8_t"); + CASE(UInt16, "uint16_t"); + CASE(UInt32, "uint32_t"); + CASE(UInt64, "uint64_t"); + CASE(Float32,"float"); + CASE(Float64,"double"); + CASE(String, "string"); + CASE(Any, "any"); + CASE(Union, "union"); + CASE(Struct, "struct"); + CASE(Null, "null"); +#undef CASE + return true; + default: + return false; + } +} + +const char* TypeCode::name() const +{ + switch(code) { +#define CASE(CASE, LBL) case TypeCode::CASE: return LBL + CASE(Bool, "bool"); + CASE(Int8, "int8_t"); + CASE(Int16, "int16_t"); + CASE(Int32, "int32_t"); + CASE(Int64, "int64_t"); + CASE(UInt8, "uint8_t"); + CASE(UInt16, "uint16_t"); + CASE(UInt32, "uint32_t"); + CASE(UInt64, "uint64_t"); + CASE(Float32,"float"); + CASE(Float64,"double"); + CASE(String, "string"); + CASE(Any, "any"); + CASE(Union, "union"); + CASE(Struct, "struct"); + CASE(Null, "null"); +#undef CASE +#define CASE(CASE, LBL) case TypeCode::CASE##A: return LBL "[]" + CASE(Bool, "bool"); + CASE(Int8, "int8_t"); + CASE(Int16, "int16_t"); + CASE(Int32, "int32_t"); + CASE(Int64, "int64_t"); + CASE(UInt8, "uint8_t"); + CASE(UInt16, "uint16_t"); + CASE(UInt32, "uint32_t"); + CASE(UInt64, "uint64_t"); + CASE(Float32,"float"); + CASE(Float64,"double"); + CASE(String, "string"); + CASE(Any, "any"); + CASE(Union, "union"); + CASE(Struct, "struct"); +#undef CASE + } + 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) +{ + if(id && 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(); + if(c!=TypeCode::Struct && c!=TypeCode::Union) + throw std::runtime_error("Only (array of) Struct or Union may have members"); + } +} + +static +void name_validate(const char *name) +{ + // [a-zA-Z_][a-zA-Z0-9_]* + + if(!name || name[0]=='\0') + throw std::runtime_error("empty field name not allowed"); + for(size_t i=0; name[i]; i++) { + char c = name[i]; + if(c>='0' && c<='9' && i>0) { + // number ok after first + } else if((c>='a' && c<='z') || (c>='A' && c<='Z')) { + // alphas ok + } else { + switch(c) { + case '_': + break; + default: + throw std::runtime_error(SB()<<"invalid field name \""<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); + } +} + +TypeDef::TypeDef(const Value& o) +{ + if(o.desc) { + root.reset(new Node(nullptr)); + copy_tree(o.desc, *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) +{ + auto code = node.code; + if(node.code==TypeCode::StructA || node.code==TypeCode::UnionA) { + + desc.emplace_back(); + auto& fld = desc.back(); + fld.code = node.code; + // struct/union array have no ID + fld.hash = node.code.code; + code = code.scalarOf(); + } + + const auto index = desc.size(); + desc.emplace_back(); + + { + auto& fld = desc.back(); + fld.code = code; + fld.id = node.id; + fld.hash = code.code ^ std::hash{}(fld.id); + } + + + for(auto& pair : node.children) { + const auto cindex = desc.size(); + + build_tree(desc, *pair.second); // recurse. may realloc desc + + auto& fld = desc[index]; + auto& child = desc[cindex]; + + fld.hash ^= std::hash{}(pair.first) ^ child.hash; + + fld.mlookup[pair.first] = cindex-index; + fld.miter.emplace_back(pair.first, cindex-index); + + std::string cname = pair.first+"."; + if(fld.code.code==TypeCode::Struct && fld.code==child.code) { + // propagate names from sub-struct + for(auto& cpair : child.mlookup) { + fld.mlookup[cname+cpair.first] = cindex-index+cpair.second; + } + } + } + + desc[index].num_index = desc.size()-index; + + if(node.code==TypeCode::StructA || node.code==TypeCode::UnionA) + { + desc[index-1].num_index = desc.size()-index+1; + } +} + +Value TypeDef::create() const +{ + if(!root) + throw std::logic_error("Empty TypeDef"); + + auto desc = std::make_shared>(); + build_tree(*desc, *root); + 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) +{ + strm<code; + if(!node->id.empty()) + strm<<" \""<id<<"\""; + if(!node->children.empty()) { + strm<<" {\n"; + for(auto& pair : node->children) { + indent(strm, level+1); + show_Node(strm, pair.first, pair.second.get(), level+1); + } + indent(strm, level); + strm.put('}'); + if(!name.empty()) + strm<<" "<\n"; + } else { + show_Node(strm, std::string(), def.root.get()); + } + return strm; +} + +namespace impl { + + +void FieldDesc_calculate_offset(FieldDesc* const top) +{ + top->offset = 0; + uint16_t offset = 1; + size_t index = 1; + while(index < top->size()) { + auto& fld = top[index]; + + switch (fld.code.code) { + case TypeCode::Struct: + if(top->code==fld.code) { + // sub-structure + fld.offset = offset++; + index++; + } else { + // structure inside union or array of struct + // new offset zero + FieldDesc_calculate_offset(top); + index+=top->size(); + } + break; + case TypeCode::Union: + // number in parent structure/union + fld.offset = offset++; + // new offset zero for each child + for(auto& pair : fld.miter) { + FieldDesc_calculate_offset(top+index+pair.second); + } + index += fld.size(); + break; + case TypeCode::StructA: + case TypeCode::UnionA: + // number in parent structure/union + fld.offset = offset++; + index++; + // new offset zero for child + FieldDesc_calculate_offset(top+index); + index += top[index].size(); + break; + default: + fld.offset = offset++; + index++; + break; + } + fld.next_offset = offset; + } + top->next_offset = offset; +} + +std::ostream& operator<<(std::ostream& strm, const FieldDesc* desc) +{ + for(auto idx : range(desc->size())) { + auto& fld = desc[idx]; + strm<<"["<" + " ["< "<::op(const char *s) return ret; } } + +void indent(std::ostream& strm, unsigned level) { + for(auto i : range(level)) { + (void)i; + strm<<" "; + } +} + }} diff --git a/src/utilpvt.h b/src/utilpvt.h index e3b0024..f2b51d6 100644 --- a/src/utilpvt.h +++ b/src/utilpvt.h @@ -53,6 +53,7 @@ inline T lexical_cast(const std::string& s) return idetail::as_str::op(s.c_str()); } +void indent(std::ostream& strm, unsigned level); namespace idetail { template