Redo FieldDesc
Follow shape of FieldStorage exactly. Avoids need for offset calculation.
This commit is contained in:
+115
-52
@@ -45,22 +45,20 @@ Value::Value(const std::shared_ptr<const impl::FieldDesc>& desc)
|
||||
auto top = std::make_shared<StructTop>();
|
||||
|
||||
top->desc = desc;
|
||||
top->valid.resize(desc->next_offset-desc->offset);
|
||||
top->member_indicies.resize(top->valid.size());
|
||||
top->members.resize(top->valid.size());
|
||||
top->members.resize(desc->size());
|
||||
{
|
||||
auto& root = top->members[0];
|
||||
root.init(desc.get());
|
||||
root.top = top.get();
|
||||
top->member_indicies[0u] = 0u;
|
||||
}
|
||||
|
||||
for(auto& pair : desc->mlookup) {
|
||||
auto cfld = desc.get() + pair.second;
|
||||
auto& mem = top->members.at(cfld->offset-desc->offset);
|
||||
mem.top = top.get();
|
||||
mem.init(cfld);
|
||||
top->member_indicies[cfld->offset-desc->offset] = pair.second;
|
||||
if(desc->code==TypeCode::Struct) {
|
||||
for(auto& pair : desc->mlookup) {
|
||||
auto cfld = desc.get() + pair.second;
|
||||
auto& mem = top->members.at(pair.second);
|
||||
mem.top = top.get();
|
||||
mem.init(cfld);
|
||||
}
|
||||
}
|
||||
|
||||
this->desc = desc.get();
|
||||
@@ -93,18 +91,89 @@ Value Value::clone() const
|
||||
if(desc) {
|
||||
decltype (store->top->desc) fld(store->top->desc, desc);
|
||||
ret = Value(fld);
|
||||
//ret.assign(*this);
|
||||
ret.assign(*this);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//Value& Value::assign(const Value& o)
|
||||
//{
|
||||
// if(desc!=o.desc)
|
||||
// throw std::runtime_error("Can only assign same TypeDef"); // TODO relax
|
||||
Value& Value::assign(const Value& o)
|
||||
{
|
||||
if(desc!=o.desc)
|
||||
throw std::runtime_error("Can only assign same TypeDef"); // TODO relax
|
||||
|
||||
// return *this;
|
||||
//}
|
||||
if(desc) {
|
||||
for(size_t bit=0, end=desc->size(); bit<end;) {
|
||||
auto sstore = o.store.get() + bit;
|
||||
auto dstore = store.get() + bit;
|
||||
|
||||
if(!sstore->valid) {
|
||||
bit++;
|
||||
continue;
|
||||
}
|
||||
|
||||
dstore->valid = true;
|
||||
|
||||
switch(dstore->code) {
|
||||
case StoreType::Real:
|
||||
case StoreType::Integer:
|
||||
case StoreType::UInteger:
|
||||
dstore->as<uint64_t>() = sstore->as<uint64_t>();
|
||||
bit++;
|
||||
break;
|
||||
case StoreType::String:
|
||||
dstore->as<std::string>() = sstore->as<std::string>();
|
||||
bit++;
|
||||
break;
|
||||
case StoreType::Array:
|
||||
dstore->as<shared_array<const void>>() = sstore->as<shared_array<const void>>();
|
||||
bit++;
|
||||
break;
|
||||
case StoreType::Compound:
|
||||
dstore->as<Value>() = sstore->as<Value>();
|
||||
bit++;
|
||||
break;
|
||||
case StoreType::Null: {
|
||||
// copy entire sub-structure
|
||||
auto sdesc = desc + bit;
|
||||
|
||||
for(auto end2 = bit + sdesc->size(); bit<end2; bit++)
|
||||
{
|
||||
auto sstore = o.store.get() + bit;
|
||||
auto dstore = store.get() + bit;
|
||||
|
||||
dstore->valid = true;
|
||||
|
||||
switch(dstore->code) {
|
||||
case StoreType::Real:
|
||||
case StoreType::Integer:
|
||||
case StoreType::UInteger:
|
||||
dstore->as<uint64_t>() = sstore->as<uint64_t>();
|
||||
bit++;
|
||||
break;
|
||||
case StoreType::String:
|
||||
dstore->as<std::string>() = sstore->as<std::string>();
|
||||
bit++;
|
||||
break;
|
||||
case StoreType::Array:
|
||||
dstore->as<shared_array<const void>>() = sstore->as<shared_array<const void>>();
|
||||
bit++;
|
||||
break;
|
||||
case StoreType::Compound:
|
||||
dstore->as<Value>() = sstore->as<Value>();
|
||||
bit++;
|
||||
break;
|
||||
case StoreType::Null: // skip sub-struct nodes, we will copy all leaf nodes
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value Value::allocMember()
|
||||
{
|
||||
@@ -112,7 +181,7 @@ Value Value::allocMember()
|
||||
if(!desc || (desc->code!=TypeCode::UnionA && desc->code!=TypeCode::StructA))
|
||||
throw std::runtime_error("allocMember() only meaningful for Struct[] or Union[]");
|
||||
|
||||
decltype (store->top->desc) fld(store->top->desc, desc+1);
|
||||
decltype (store->top->desc) fld(store->top->desc, desc->members.data());
|
||||
return Value::Helper::build(fld, *this);
|
||||
}
|
||||
|
||||
@@ -121,28 +190,29 @@ bool Value::isMarked(bool parents, bool children) const
|
||||
if(!desc)
|
||||
return false;
|
||||
|
||||
if(store->top->valid[store->index()])
|
||||
if(store->valid)
|
||||
return true;
|
||||
|
||||
auto top = store->top;
|
||||
|
||||
if(children && desc->size()>1u) {
|
||||
// TODO more efficient
|
||||
for(auto bit : range(desc->offset-top->desc->offset,
|
||||
desc->next_offset-top->desc->offset))
|
||||
for(auto bit : range(desc->size()))
|
||||
{
|
||||
if(top->valid[bit])
|
||||
auto cstore = store.get() + bit;
|
||||
if(cstore->valid)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(parents) {
|
||||
auto P = desc;
|
||||
while(P!=top->desc.get()) {
|
||||
P -= P->parent_index;
|
||||
auto pdesc = desc;
|
||||
auto pstore = store.get();
|
||||
while(pdesc!=top->desc.get()) {
|
||||
pdesc -= pdesc->parent_index;
|
||||
pstore -= pdesc->parent_index;
|
||||
|
||||
auto bit = P->offset - top->desc->offset;
|
||||
if(top->valid[bit])
|
||||
if(pstore->valid)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -155,7 +225,7 @@ void Value::mark(bool v)
|
||||
if(!desc)
|
||||
return;
|
||||
|
||||
store->top->valid[store->index()] = v;
|
||||
store->valid = v;
|
||||
if(!v)
|
||||
return;
|
||||
|
||||
@@ -171,26 +241,26 @@ void Value::unmark(bool parents, bool children)
|
||||
if(!desc)
|
||||
return;
|
||||
|
||||
store->top->valid[store->index()] = false;
|
||||
store->valid = false;
|
||||
|
||||
auto top = store->top;
|
||||
|
||||
if(children && desc->size()>1u) {
|
||||
// TODO more efficient
|
||||
for(auto bit : range(desc->offset-top->desc->offset,
|
||||
desc->next_offset-top->desc->offset))
|
||||
for(auto bit : range(desc->size()))
|
||||
{
|
||||
top->valid[bit] = false;
|
||||
(store.get() + bit)->valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(parents) {
|
||||
auto P = desc;
|
||||
while(P!=top->desc.get()) {
|
||||
P -= P->parent_index;
|
||||
auto pdesc = desc;
|
||||
auto pstore = store.get();
|
||||
while(pdesc!=top->desc.get()) {
|
||||
pdesc -= pdesc->parent_index;
|
||||
pstore -= pdesc->parent_index;
|
||||
|
||||
auto bit = P->offset - top->desc->offset;
|
||||
top->valid[bit] = false;
|
||||
pstore->valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,7 +435,7 @@ void Value::copyIn(const void *ptr, StoreType type)
|
||||
if(desc->code!=TypeCode::AnyA) {
|
||||
// enforce member type for Struct[] and Union[]
|
||||
for(auto& val : tsrc) {
|
||||
if(val.desc && val.desc!=desc+1) {
|
||||
if(val.desc && val.desc!=desc->members.data()) {
|
||||
throw NoConvert();
|
||||
}
|
||||
}
|
||||
@@ -397,12 +467,6 @@ void Value::copyIn(const void *ptr, StoreType type)
|
||||
}
|
||||
throw NoConvert();
|
||||
case StoreType::Null:
|
||||
if(desc->code==TypeCode::Struct && type==StoreType::Compound) {
|
||||
auto& val = *reinterpret_cast<const Value*>(ptr);
|
||||
if(val.desc && val.desc->code==TypeCode::Struct) {
|
||||
// Struct to Struct assignment.
|
||||
}
|
||||
}
|
||||
throw NoConvert();
|
||||
}
|
||||
|
||||
@@ -430,7 +494,7 @@ void Value::traverse(const std::string &expr, bool modify)
|
||||
if(desc!=store->top->desc.get())
|
||||
{
|
||||
auto pdesc = desc - desc->parent_index;
|
||||
std::shared_ptr<FieldStorage> pstore(store, store.get() - desc->offset + pdesc->offset);
|
||||
std::shared_ptr<FieldStorage> pstore(store, store.get() - desc->parent_index);
|
||||
store = std::move(pstore);
|
||||
desc = pdesc;
|
||||
pos++;
|
||||
@@ -454,8 +518,7 @@ void Value::traverse(const std::string &expr, bool modify)
|
||||
if(sep>0 && (it=desc->mlookup.find(expr.substr(pos, sep-pos)))!=desc->mlookup.end()) {
|
||||
// found it
|
||||
auto next = desc+it->second;
|
||||
auto offset = next->offset - desc->offset;
|
||||
decltype(store) value(store, store.get()+offset);
|
||||
decltype(store) value(store, store.get()+it->second);
|
||||
store = std::move(value);
|
||||
desc = next;
|
||||
pos = sep;
|
||||
@@ -487,11 +550,11 @@ void Value::traverse(const std::string &expr, bool modify)
|
||||
// found it.
|
||||
auto& fld = store->as<Value>();
|
||||
|
||||
if(modify || fld.desc==desc+it->second) {
|
||||
if(modify || fld.desc==&desc->members[it->second]) {
|
||||
// will select, or already selected
|
||||
if(fld.desc!=desc+it->second) {
|
||||
if(fld.desc!=&desc->members[it->second]) {
|
||||
// select
|
||||
std::shared_ptr<const FieldDesc> mtype(store->top->desc, desc+it->second);
|
||||
std::shared_ptr<const FieldDesc> mtype(store->top->desc, &desc->members[it->second]);
|
||||
fld = Value(mtype, *this);
|
||||
}
|
||||
pos = sep;
|
||||
@@ -593,7 +656,7 @@ void show_Value(std::ostream& strm,
|
||||
strm<<" {\n";
|
||||
for(auto& pair : desc->miter) {
|
||||
auto cdesc = desc + pair.second;
|
||||
show_Value(strm, pair.first, cdesc, store - desc->offset + cdesc->offset, level+1);
|
||||
show_Value(strm, pair.first, cdesc, store + pair.second, level+1);
|
||||
}
|
||||
indent(strm, level);
|
||||
strm<<"}";
|
||||
@@ -612,7 +675,7 @@ void show_Value(std::ostream& strm,
|
||||
auto& fld = store->as<Value>();
|
||||
if(fld.valid() && desc->code==TypeCode::Union) {
|
||||
for(auto& pair : desc->miter) {
|
||||
if(desc + pair.second == Value::Helper::desc(fld)) {
|
||||
if(&desc->members[pair.second] == Value::Helper::desc(fld)) {
|
||||
strm<<"."<<pair.first;
|
||||
break;
|
||||
}
|
||||
|
||||
+81
-71
@@ -41,11 +41,10 @@ void to_wire(Buffer& buf, const FieldDesc* cur)
|
||||
switch(cur->code.code) {
|
||||
case TypeCode::StructA:
|
||||
case TypeCode::UnionA:
|
||||
to_wire(buf, cur+1);
|
||||
to_wire(buf, &cur->members[0]);
|
||||
break;
|
||||
|
||||
case TypeCode::Struct:
|
||||
case TypeCode::Union:
|
||||
to_wire(buf, cur->id);
|
||||
to_wire(buf, Size{cur->miter.size()});
|
||||
for(auto& pair : cur->miter) {
|
||||
@@ -53,12 +52,21 @@ void to_wire(Buffer& buf, const FieldDesc* cur)
|
||||
to_wire(buf, cur+pair.second); // jump forward in FieldDesc array and recurse!
|
||||
}
|
||||
break;
|
||||
|
||||
case TypeCode::Union:
|
||||
to_wire(buf, cur->id);
|
||||
to_wire(buf, Size{cur->miter.size()});
|
||||
for(auto& pair : cur->miter) {
|
||||
to_wire(buf, pair.first);
|
||||
to_wire(buf, &cur->members[pair.second]); // jump forward in FieldDesc array and recurse!
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void from_wire(Buffer& buf, TypeDeserContext& ctxt, unsigned depth)
|
||||
void from_wire(Buffer& buf, std::vector<FieldDesc>& descs, TypeStore& cache, unsigned depth)
|
||||
{
|
||||
if(!buf.good() || depth>20) {
|
||||
buf.fault();
|
||||
@@ -67,7 +75,7 @@ void from_wire(Buffer& buf, TypeDeserContext& ctxt, unsigned depth)
|
||||
|
||||
TypeCode code;
|
||||
from_wire(buf, code.code);
|
||||
const size_t index = ctxt.descs.size(); // index of first node we add to ctxt.descs[]
|
||||
const size_t index = descs.size(); // index of first node we add to descs[]
|
||||
|
||||
if(code == TypeCode::Null) {
|
||||
return;
|
||||
@@ -76,26 +84,28 @@ void from_wire(Buffer& buf, TypeDeserContext& ctxt, unsigned depth)
|
||||
// update cache
|
||||
uint16_t key=0;
|
||||
from_wire(buf, key);
|
||||
from_wire(buf, ctxt, depth+1u);
|
||||
if(!buf.good() || index==ctxt.descs.size()) {
|
||||
from_wire(buf, descs, cache, depth+1u);
|
||||
if(!buf.good() || index==descs.size()) {
|
||||
buf.fault();
|
||||
return;
|
||||
|
||||
} else {
|
||||
auto& entry = ctxt.cache[key];
|
||||
auto& entry = cache[key];
|
||||
// copy new node, and any decendents into cache
|
||||
entry.resize(ctxt.descs.size()-index);
|
||||
std::copy(ctxt.descs.begin()+index,
|
||||
ctxt.descs.end(),
|
||||
entry.resize(descs.size()-index);
|
||||
std::copy(descs.begin()+index,
|
||||
descs.end(),
|
||||
entry.begin());
|
||||
|
||||
descs[index].parent_index = 0u; // our caller will set if actually is a parent.
|
||||
}
|
||||
|
||||
} else if(code.code==0xfe) {
|
||||
// fetch cache
|
||||
uint16_t key=0;
|
||||
from_wire(buf, key);
|
||||
auto it = ctxt.cache.find(key);
|
||||
if(it==ctxt.cache.end()) {
|
||||
auto it = cache.find(key);
|
||||
if(it==cache.end()) {
|
||||
buf.fault();
|
||||
}
|
||||
|
||||
@@ -105,10 +115,10 @@ void from_wire(Buffer& buf, TypeDeserContext& ctxt, unsigned depth)
|
||||
|
||||
} else {
|
||||
// copy from cache
|
||||
ctxt.descs.resize(index+it->second.size());
|
||||
descs.resize(index+it->second.size());
|
||||
std::copy(it->second.begin(),
|
||||
it->second.end(),
|
||||
ctxt.descs.begin()+index);
|
||||
descs.begin()+index);
|
||||
}
|
||||
|
||||
} else if(code.code!=0xff && code.code&0x10) {
|
||||
@@ -118,9 +128,9 @@ void from_wire(Buffer& buf, TypeDeserContext& ctxt, unsigned depth)
|
||||
} else {
|
||||
// actual field
|
||||
|
||||
ctxt.descs.emplace_back();
|
||||
descs.emplace_back();
|
||||
{
|
||||
auto& fld = ctxt.descs.back();
|
||||
auto& fld = descs.back();
|
||||
|
||||
fld.code = code;
|
||||
fld.hash = code.code;
|
||||
@@ -129,8 +139,8 @@ void from_wire(Buffer& buf, TypeDeserContext& ctxt, unsigned depth)
|
||||
switch(code.code) {
|
||||
case TypeCode::StructA:
|
||||
case TypeCode::UnionA:
|
||||
from_wire(buf, ctxt, depth+1);
|
||||
if(!buf.good() || ctxt.descs.size()==index || ctxt.descs[index+1].code!=code.scalarOf()) {
|
||||
from_wire(buf, descs.back().members, cache, depth+1);
|
||||
if(!buf.good() || descs.back().members.empty() || descs.back().members[0].code!=code.scalarOf()) {
|
||||
buf.fault();
|
||||
return;
|
||||
}
|
||||
@@ -138,40 +148,45 @@ void from_wire(Buffer& buf, TypeDeserContext& ctxt, unsigned depth)
|
||||
|
||||
case TypeCode::Struct:
|
||||
case TypeCode::Union: {
|
||||
from_wire(buf, ctxt.descs.back().id);
|
||||
from_wire(buf, descs.back().id);
|
||||
|
||||
Size nfld{0};
|
||||
std::string name;
|
||||
from_wire(buf, nfld); // number of children
|
||||
{
|
||||
auto& fld = ctxt.descs.back();
|
||||
auto& fld = descs.back();
|
||||
|
||||
fld.miter.reserve(nfld.size);
|
||||
fld.hash ^= std::hash<std::string>{}(fld.id);
|
||||
}
|
||||
|
||||
auto& cdescs = code.code==TypeCode::Struct ? descs : descs.back().members;
|
||||
auto cref = code.code==TypeCode::Struct ? index : 0u;
|
||||
|
||||
for(auto i: range(nfld.size)) {
|
||||
(void)i;
|
||||
const size_t cindex = ctxt.descs.size(); // index of this child
|
||||
const size_t cindex = cdescs.size(); // index of this child
|
||||
|
||||
from_wire(buf, name);
|
||||
from_wire(buf, ctxt, depth+1);
|
||||
if(!buf.good() || cindex>=ctxt.descs.size()) {
|
||||
from_wire(buf, cdescs, cache, depth+1);
|
||||
if(!buf.good() || cindex>=cdescs.size()) {
|
||||
buf.fault();
|
||||
return;
|
||||
}
|
||||
|
||||
// descs may be re-allocated (invalidating previous refs.)
|
||||
auto& fld = ctxt.descs[index];
|
||||
auto& cfld = ctxt.descs[cindex];
|
||||
cfld.parent_index = cindex-index;
|
||||
auto& fld = descs[index];
|
||||
auto& cfld = cdescs[cindex];
|
||||
if(code.code==TypeCode::Struct)
|
||||
cfld.parent_index = cindex-cref;
|
||||
|
||||
// update hash
|
||||
// TODO investigate better ways to combine hashes
|
||||
fld.hash ^= std::hash<std::string>{}(name) ^ cfld.hash;
|
||||
|
||||
// update field refs.
|
||||
fld.miter.emplace_back(name, cindex-index);
|
||||
fld.mlookup[name] = cindex-index;
|
||||
fld.miter.emplace_back(name, cindex-cref);
|
||||
fld.mlookup[name] = cindex-cref;
|
||||
name+='.';
|
||||
|
||||
if(code.code==TypeCode::Struct && code==cfld.code) {
|
||||
@@ -206,8 +221,6 @@ void from_wire(Buffer& buf, TypeDeserContext& ctxt, unsigned depth)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.descs[index].num_index = ctxt.descs.size()-index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,10 +258,9 @@ void to_wire_field(Buffer& buf, const FieldDesc* desc, const std::shared_ptr<con
|
||||
case StoreType::Null:
|
||||
switch(desc->code.code) {
|
||||
case TypeCode::Struct: {
|
||||
auto& top = *store->top;
|
||||
// serialize entire sub-structure
|
||||
for(auto off : range(desc->offset-top.desc->offset+1u, desc->next_offset-top.desc->offset)) {
|
||||
auto cdesc = desc + top.member_indicies[off];
|
||||
for(auto off : range(desc->size())) {
|
||||
auto cdesc = desc + off;
|
||||
std::shared_ptr<const FieldStorage> cstore(store, store.get()+off); // TODO avoid shared_ptr/aliasing here
|
||||
if(cdesc->code!=TypeCode::Struct)
|
||||
to_wire_field(buf, cdesc, cstore);
|
||||
@@ -309,7 +321,7 @@ void to_wire_field(Buffer& buf, const FieldDesc* desc, const std::shared_ptr<con
|
||||
} else {
|
||||
size_t index = 0u;
|
||||
for(auto& pair : desc->miter) {
|
||||
if(Value::Helper::desc(fld)== desc+pair.second)
|
||||
if(Value::Helper::desc(fld)== &desc->members[pair.second])
|
||||
break;
|
||||
index++;
|
||||
}
|
||||
@@ -368,7 +380,7 @@ void to_wire_field(Buffer& buf, const FieldDesc* desc, const std::shared_ptr<con
|
||||
to_wire(buf, uint8_t(0u));
|
||||
} else {
|
||||
to_wire(buf, uint8_t(1u));
|
||||
assert(Value::Helper::desc(elem)==desc+1);
|
||||
assert(Value::Helper::desc(elem)==&desc->members[0]);
|
||||
to_wire_full(buf, elem);
|
||||
}
|
||||
}
|
||||
@@ -424,19 +436,23 @@ void to_wire_valid(Buffer& buf, const Value& val)
|
||||
{
|
||||
auto desc = Value::Helper::desc(val);
|
||||
auto store = Value::Helper::store(val);
|
||||
assert(!!desc);
|
||||
auto top = store->top;
|
||||
assert(desc && desc->code==TypeCode::Struct);
|
||||
|
||||
to_wire(buf, top->valid);
|
||||
top->valid.resize(top->members.size());
|
||||
BitMask valid(desc->size());
|
||||
|
||||
for(auto bit : range(desc->size())) {
|
||||
if((store.get()+bit)->valid)
|
||||
valid[bit] = true;
|
||||
}
|
||||
|
||||
to_wire(buf, valid);
|
||||
|
||||
for(auto bit : range(desc->size())) {
|
||||
if(!(store.get()+bit)->valid)
|
||||
continue;
|
||||
|
||||
// iterate marked fields
|
||||
for(auto bit = top->valid.findSet(desc->offset-top->desc->offset);
|
||||
bit<desc->next_offset-top->desc->offset;
|
||||
bit = top->valid.findSet(bit+1))
|
||||
{
|
||||
std::shared_ptr<const FieldStorage> cstore(store, store.get()+bit);
|
||||
to_wire_field(buf, desc + top->member_indicies[bit], cstore);
|
||||
to_wire_field(buf, desc+bit, cstore);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,14 +473,13 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const
|
||||
case StoreType::Null:
|
||||
switch(desc->code.code) {
|
||||
case TypeCode::Struct: {
|
||||
auto& top = *store->top;
|
||||
// serialize entire sub-structure
|
||||
for(auto off : range(desc->offset-top.desc->offset+1u, desc->next_offset-top.desc->offset)) {
|
||||
auto cdesc = desc + top.member_indicies[off];
|
||||
for(auto off : range(desc->size())) {
|
||||
auto cdesc = desc + off;
|
||||
std::shared_ptr<FieldStorage> cstore(store, store.get()+off); // TODO avoid shared_ptr/aliasing here
|
||||
if(cdesc->code!=TypeCode::Struct) {
|
||||
from_wire_field(buf, ctxt, cdesc, cstore);
|
||||
top.valid[cstore->index()] = true;
|
||||
cstore->valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -524,7 +539,7 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const
|
||||
|
||||
} else if(select.size < desc->miter.size()) {
|
||||
std::shared_ptr<const FieldDesc> stype(store->top->desc,
|
||||
desc + desc->miter[select.size].second); // alias
|
||||
&desc->members[desc->miter[select.size].second]); // alias
|
||||
fld = Value::Helper::build(stype, store, desc);
|
||||
|
||||
from_wire_full(buf, ctxt, fld);
|
||||
@@ -535,9 +550,8 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const
|
||||
|
||||
case TypeCode::Any: {
|
||||
auto descs(std::make_shared<std::vector<FieldDesc>>());
|
||||
TypeDeserContext dc{*descs, ctxt};
|
||||
|
||||
from_wire(buf, dc);
|
||||
from_wire(buf, *descs, ctxt);
|
||||
if(!buf.good())
|
||||
return;
|
||||
|
||||
@@ -546,8 +560,6 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const
|
||||
return;
|
||||
|
||||
} else {
|
||||
FieldDesc_calculate_offset(descs->data());
|
||||
|
||||
std::shared_ptr<const FieldDesc> stype(descs, descs->data()); // alias
|
||||
fld = Value::Helper::build(stype);
|
||||
|
||||
@@ -594,7 +606,7 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const
|
||||
from_wire(buf, alen);
|
||||
shared_array<Value> arr(alen.size);
|
||||
std::shared_ptr<const FieldDesc> etype(store->top->desc,
|
||||
desc + 1); // alias
|
||||
&desc->members[0]); // alias
|
||||
for(auto& elem : arr) {
|
||||
if(from_wire_as<uint8_t>(buf)!=0) { // strictly 1 or 0
|
||||
elem = Value::Helper::build(etype, store, desc);
|
||||
@@ -610,7 +622,7 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const
|
||||
Size alen{};
|
||||
from_wire(buf, alen);
|
||||
shared_array<Value> arr(alen.size);
|
||||
auto cdesc = desc+1;
|
||||
auto cdesc = &desc->members[0];
|
||||
|
||||
for(auto& elem : arr) {
|
||||
if(from_wire_as<uint8_t>(buf)!=0) { // strictly 1 or 0
|
||||
@@ -622,7 +634,7 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const
|
||||
|
||||
} else if(select.size < cdesc->miter.size()) {
|
||||
std::shared_ptr<const FieldDesc> stype(store->top->desc,
|
||||
cdesc + cdesc->miter[select.size].second); // alias
|
||||
&cdesc->members[cdesc->miter[select.size].second]); // alias
|
||||
elem = Value::Helper::build(stype, store, desc);
|
||||
|
||||
from_wire_full(buf, ctxt, elem);
|
||||
@@ -646,14 +658,12 @@ void from_wire_field(Buffer& buf, TypeStore& ctxt, const FieldDesc* desc, const
|
||||
for(auto& elem : arr) {
|
||||
if(from_wire_as<uint8_t>(buf)!=0) { // strictly 1 or 0
|
||||
auto descs(std::make_shared<std::vector<FieldDesc>>());
|
||||
TypeDeserContext dc{*descs, ctxt};
|
||||
|
||||
from_wire(buf, dc);
|
||||
from_wire(buf, *descs, ctxt);
|
||||
if(!buf.good())
|
||||
return;
|
||||
|
||||
if(!descs->empty()) {
|
||||
FieldDesc_calculate_offset(descs->data());
|
||||
|
||||
std::shared_ptr<const FieldDesc> stype(descs, descs->data()); // alias
|
||||
elem = Value::Helper::build(stype, store, desc);
|
||||
@@ -690,33 +700,33 @@ void from_wire_valid(Buffer& buf, TypeStore& ctxt, Value& val)
|
||||
assert(!!desc);
|
||||
auto top = store->top;
|
||||
|
||||
from_wire(buf, top->valid);
|
||||
BitMask valid;
|
||||
from_wire(buf, valid);
|
||||
// encoding rounds # of bits to whole bytes, so we may trim
|
||||
top->valid.resize(top->members.size());
|
||||
valid.resize(top->members.size());
|
||||
if(!buf.good())
|
||||
return;
|
||||
|
||||
for(auto bit = top->valid.findSet(desc->offset-top->desc->offset);
|
||||
bit<(desc->next_offset-top->desc->offset);
|
||||
bit = top->valid.findSet(bit+1))
|
||||
for(auto bit = valid.findSet(0u);
|
||||
bit<desc->size();)
|
||||
{
|
||||
std::shared_ptr<FieldStorage> cstore(store, store.get()+bit-desc->offset);
|
||||
from_wire_field(buf, ctxt, desc + top->member_indicies[bit], cstore);
|
||||
top->valid[bit] = true;
|
||||
std::shared_ptr<FieldStorage> cstore(store, store.get()+bit);
|
||||
auto cdesc = desc + bit;
|
||||
from_wire_field(buf, ctxt, cdesc, cstore);
|
||||
cstore->valid = true;
|
||||
bit = valid.findSet(bit + cdesc->size());
|
||||
}
|
||||
}
|
||||
|
||||
void from_wire_type_value(Buffer& buf, TypeStore& ctxt, Value& val)
|
||||
{
|
||||
auto descs(std::make_shared<std::vector<FieldDesc>>());
|
||||
TypeDeserContext dc{*descs, ctxt};
|
||||
|
||||
from_wire(buf, dc);
|
||||
from_wire(buf, *descs, ctxt);
|
||||
if(!buf.good())
|
||||
return;
|
||||
|
||||
if(!descs->empty()) {
|
||||
FieldDesc_calculate_offset(descs->data());
|
||||
|
||||
std::shared_ptr<const FieldDesc> stype(descs, descs->data()); // alias
|
||||
val = Value::Helper::build(stype);
|
||||
|
||||
+18
-23
@@ -53,30 +53,36 @@ struct Buffer;
|
||||
* Relative to current FieldDesc*.
|
||||
*/
|
||||
struct FieldDesc {
|
||||
// type ID string (struct/union)
|
||||
// type ID string (Struct/Union)
|
||||
std::string id;
|
||||
|
||||
// Lookup of all decendent fields of this Structure or Union.
|
||||
// "fld.sub.leaf" -> rel index in enclosing vector<FieldDesc>
|
||||
// "fld.sub.leaf" -> rel index
|
||||
// For Struct, relative to this
|
||||
// For Union, offset in members array
|
||||
std::map<std::string, size_t> mlookup;
|
||||
|
||||
// child iteration. child# -> ("sub", rel index in enclosing vector<FieldDesc>)
|
||||
std::vector<std::pair<std::string, size_t>> miter;
|
||||
|
||||
// hash of this type (aggragating from children)
|
||||
// created using the code ^ id ^ (child_name ^ child_hash)*N
|
||||
size_t hash;
|
||||
// abs. offset in enclosing StructTop::members. (not abs. offset of FieldDesc array)
|
||||
// used to navigate vector<FieldStorage>
|
||||
size_t offset=0, next_offset=0;
|
||||
// number of FieldDesc nodes which describe this node and decendents. Inclusive. always >=1
|
||||
// eg. num_index+(FieldDesc*)this jumps to next sibling
|
||||
size_t num_index=0;
|
||||
// number of FieldDesc nodes between this node and it's a parent node (if any).
|
||||
|
||||
// number of FieldDesc nodes between this node and it's a parent Struct (or 0 if no parent).
|
||||
// This value also appears in the parent's miter and mlookup mappings.
|
||||
// Only usable when a StructTop is accessible and this!=StructTop::desc
|
||||
size_t parent_index=0;
|
||||
|
||||
// For Union, UnionA, StructA
|
||||
// For Union, the choices
|
||||
// For UnionA/StructA, size()==1 containing a Union/Struct
|
||||
std::vector<FieldDesc> members;
|
||||
|
||||
TypeCode code{TypeCode::Null};
|
||||
|
||||
// number of FieldDesc nodes which describe this node. Inclusive. always size()>=1
|
||||
inline size_t size() const { return num_index; }
|
||||
inline size_t size() const { return 1u + (members.empty() ? mlookup.size() : 0u); }
|
||||
};
|
||||
|
||||
PVXS_API
|
||||
@@ -84,13 +90,8 @@ void to_wire(Buffer& buf, const FieldDesc* cur);
|
||||
|
||||
typedef std::map<uint16_t, std::vector<FieldDesc>> TypeStore;
|
||||
|
||||
struct TypeDeserContext {
|
||||
std::vector<FieldDesc>& descs;
|
||||
TypeStore& cache;
|
||||
};
|
||||
|
||||
PVXS_API
|
||||
void from_wire(Buffer& buf, TypeDeserContext& ctxt, unsigned depth=0);
|
||||
void from_wire(Buffer& buf, std::vector<FieldDesc>& descs, TypeStore& cache, unsigned depth=0);
|
||||
|
||||
struct StructTop;
|
||||
|
||||
@@ -113,6 +114,7 @@ struct FieldStorage {
|
||||
>::type store;
|
||||
// index of this field in StructTop::members
|
||||
StructTop *top;
|
||||
bool valid=false;
|
||||
StoreType code=StoreType::Null; // duplicates associated FieldDesc::code
|
||||
|
||||
void init(const FieldDesc* desc);
|
||||
@@ -132,13 +134,9 @@ struct FieldStorage {
|
||||
|
||||
// hidden (publicly) management of an allocated Struct
|
||||
struct StructTop {
|
||||
// which members have been assigned/updated (use to track "changes")
|
||||
BitMask valid;
|
||||
// type of first top level struct. always !NULL.
|
||||
// Actually the first element of a vector<const FieldDesc>
|
||||
std::shared_ptr<const FieldDesc> desc;
|
||||
// map from FieldStorage offsets to FieldDesc offsets. inverse of FieldDesc::offset
|
||||
std::vector<size_t> member_indicies;
|
||||
// our members (inclusive). always size()>=1
|
||||
std::vector<FieldStorage> members;
|
||||
|
||||
@@ -164,9 +162,6 @@ void from_wire_valid(Buffer& buf, TypeStore& ctxt, Value& val);
|
||||
PVXS_API
|
||||
void from_wire_type_value(Buffer& buf, TypeStore& ctxt, Value& val);
|
||||
|
||||
PVXS_API
|
||||
void FieldDesc_calculate_offset(FieldDesc* top);
|
||||
|
||||
PVXS_API
|
||||
std::ostream& operator<<(std::ostream& strm, const FieldDesc* desc);
|
||||
|
||||
|
||||
+1
-1
@@ -354,7 +354,7 @@ public:
|
||||
//! allocate new storage and copy in our values
|
||||
Value clone() const;
|
||||
//! copy values from other. Must have matching types.
|
||||
// Value& assign(const Value&);
|
||||
Value& assign(const Value&);
|
||||
|
||||
//! Use to allocate members for an array of Struct and array of Union
|
||||
Value allocMember();
|
||||
|
||||
+89
-112
@@ -164,62 +164,6 @@ TypeDef::TypeDef(const Value& o)
|
||||
|
||||
TypeDef::~TypeDef() {}
|
||||
|
||||
static
|
||||
void build_tree(std::vector<FieldDesc>& desc, const Member& 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<std::string>{}(fld.id);
|
||||
}
|
||||
|
||||
|
||||
for(auto& cnode : node.children) {
|
||||
const auto cindex = desc.size();
|
||||
|
||||
build_tree(desc, cnode); // recurse. may realloc desc
|
||||
|
||||
auto& fld = desc[index];
|
||||
auto& child = desc[cindex];
|
||||
child.parent_index = cindex-index;
|
||||
|
||||
fld.hash ^= std::hash<std::string>{}(cnode.name) ^ child.hash;
|
||||
|
||||
fld.mlookup[cnode.name] = cindex-index;
|
||||
fld.miter.emplace_back(cnode.name, cindex-index);
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void append_tree(Member& node, const Member& adopt)
|
||||
{
|
||||
@@ -266,6 +210,66 @@ TypeDef& TypeDef::operator+=(std::initializer_list<Member> children)
|
||||
return *this;
|
||||
}
|
||||
|
||||
static
|
||||
void build_tree(std::vector<FieldDesc>& desc, const Member& 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;
|
||||
|
||||
Member next{code.scalarOf(), node.name};
|
||||
next.id = node.id;
|
||||
next.children = node.children; // TODO ick copy
|
||||
|
||||
build_tree(desc.back().members, next);
|
||||
return;
|
||||
}
|
||||
|
||||
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<std::string>{}(fld.id);
|
||||
}
|
||||
|
||||
auto& cdescs = code.code==TypeCode::Struct ? desc : desc.back().members;
|
||||
auto cref = code.code==TypeCode::Struct ? index : 0u;
|
||||
|
||||
for(auto& cnode : node.children) {
|
||||
const auto cindex = cdescs.size();
|
||||
|
||||
build_tree(cdescs, cnode); // recurse. may realloc desc
|
||||
|
||||
auto& fld = desc[index];
|
||||
auto& child = cdescs[cindex];
|
||||
if(code.code==TypeCode::Struct)
|
||||
child.parent_index = cindex-cref;
|
||||
|
||||
fld.hash ^= std::hash<std::string>{}(cnode.name) ^ child.hash;
|
||||
|
||||
fld.mlookup[cnode.name] = cindex-cref;
|
||||
fld.miter.emplace_back(cnode.name, cindex-cref);
|
||||
|
||||
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) {
|
||||
fld.mlookup[cname+cpair.first] = cindex-cref+cpair.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(desc.size()==index+desc[index].size());
|
||||
}
|
||||
|
||||
Value TypeDef::create() const
|
||||
{
|
||||
if(!top)
|
||||
@@ -273,7 +277,6 @@ Value TypeDef::create() const
|
||||
|
||||
auto desc = std::make_shared<std::vector<FieldDesc>>();
|
||||
build_tree(*desc, *top);
|
||||
FieldDesc_calculate_offset(desc->data());
|
||||
|
||||
std::shared_ptr<const FieldDesc> type(desc, desc->data()); // alias
|
||||
return Value(type);
|
||||
@@ -315,79 +318,53 @@ std::ostream& operator<<(std::ostream& strm, const TypeDef& def)
|
||||
|
||||
namespace impl {
|
||||
|
||||
|
||||
void FieldDesc_calculate_offset(FieldDesc* const top)
|
||||
void show_FieldDesc(std::ostream& strm, const FieldDesc* desc, unsigned level)
|
||||
{
|
||||
top->offset = 0;
|
||||
uint16_t offset = 1;
|
||||
for(size_t index = 1; index < top->size(); ) {
|
||||
auto& fld = top[index];
|
||||
for(auto idx : range(desc->size())) {
|
||||
auto& fld = desc[idx];
|
||||
indent(strm, level);
|
||||
strm<<"["<<idx<<"] "<<fld.code<<' '<<fld.id
|
||||
<<" parent=["<<(idx-fld.parent_index) <<"]"
|
||||
" ["<<idx<<":"<<idx+fld.size()<<")\n";
|
||||
|
||||
switch (fld.code.code) {
|
||||
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();
|
||||
// note: need to ensure stable lexical iteration order if fld.mlookup ever becomes unordered_map
|
||||
for(auto& pair : fld.mlookup) {
|
||||
indent(strm, level);
|
||||
strm<<" "<<pair.first<<" -> "<<pair.second<<" ["<<(idx+pair.second)<<"]\n";
|
||||
}
|
||||
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);
|
||||
indent(strm, level);
|
||||
strm<<" "<<pair.first<<" : "<<pair.second<<" ["<<(idx+pair.second)<<"]\n";
|
||||
}
|
||||
index += fld.size();
|
||||
break;
|
||||
|
||||
case TypeCode::Union:
|
||||
for(auto& pair : fld.mlookup) {
|
||||
indent(strm, level);
|
||||
strm<<" "<<pair.first<<" -> "<<pair.second<<" ["<<(pair.second)<<"]\n";
|
||||
}
|
||||
for(auto& pair : fld.miter) {
|
||||
indent(strm, level);
|
||||
strm<<" "<<pair.first<<" : "<<pair.second<<" ["<<(pair.second)<<"]\n";
|
||||
show_FieldDesc(strm, fld.members.data()+pair.second, level+1u);
|
||||
}
|
||||
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();
|
||||
show_FieldDesc(strm, fld.members.data(), level+1u);
|
||||
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<<"["<<idx<<"] "<<fld.code<<' '<<fld.id
|
||||
<<" <"<<fld.offset<<":"<<fld.next_offset<<">"
|
||||
" ["<<idx<<":"<<idx+fld.num_index<<")\n";
|
||||
|
||||
switch(fld.code.code) {
|
||||
case TypeCode::Struct:
|
||||
case TypeCode::Union: {
|
||||
// note: need to ensure stable lexical iteration order if fld.mlookup ever becomes unordered_map
|
||||
for(auto& pair : fld.mlookup) {
|
||||
strm<<" "<<pair.first<<" -> "<<pair.second<<" ["<<(idx+pair.second)<<"]\n";
|
||||
}
|
||||
for(auto& pair : fld.miter) {
|
||||
strm<<" "<<pair.first<<" : "<<pair.second<<" ["<<(idx+pair.second)<<"]\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
show_FieldDesc(strm, desc, 0u);
|
||||
return strm;
|
||||
}
|
||||
|
||||
|
||||
+87
-1
@@ -160,6 +160,68 @@ TypeDef simpledef(TypeCode::Struct, "simple_t", {
|
||||
}),
|
||||
});
|
||||
|
||||
void testSimpleDef()
|
||||
{
|
||||
testDiag("%s", __func__);
|
||||
|
||||
auto val = simpledef.create();
|
||||
|
||||
testEq(std::string(SB()<<"\n"<<Value::Helper::desc(val)),
|
||||
R"out(
|
||||
[0] struct simple_t parent=[0] [0:11)
|
||||
achoice -> 10 [10]
|
||||
any -> 7 [7]
|
||||
anya -> 8 [8]
|
||||
arbitrary -> 5 [5]
|
||||
arbitrary.sarr -> 6 [6]
|
||||
choice -> 9 [9]
|
||||
timeStamp -> 2 [2]
|
||||
timeStamp.nanoseconds -> 4 [4]
|
||||
timeStamp.secondsPastEpoch -> 3 [3]
|
||||
value -> 1 [1]
|
||||
value : 1 [1]
|
||||
timeStamp : 2 [2]
|
||||
arbitrary : 5 [5]
|
||||
any : 7 [7]
|
||||
anya : 8 [8]
|
||||
choice : 9 [9]
|
||||
achoice : 10 [10]
|
||||
[1] double[] parent=[0] [1:2)
|
||||
[2] struct time_t parent=[0] [2:5)
|
||||
nanoseconds -> 2 [4]
|
||||
secondsPastEpoch -> 1 [3]
|
||||
secondsPastEpoch : 1 [3]
|
||||
nanoseconds : 2 [4]
|
||||
[3] uint64_t parent=[2] [3:4)
|
||||
[4] uint32_t parent=[2] [4:5)
|
||||
[5] struct parent=[0] [5:7)
|
||||
sarr -> 1 [6]
|
||||
sarr : 1 [6]
|
||||
[6] struct[] parent=[5] [6:7)
|
||||
[0] struct parent=[0] [0:2)
|
||||
value -> 1 [1]
|
||||
value : 1 [1]
|
||||
[1] uint32_t parent=[0] [1:2)
|
||||
[7] any parent=[0] [7:8)
|
||||
[8] any[] parent=[0] [8:9)
|
||||
[9] union parent=[0] [9:10)
|
||||
a -> 0 [0]
|
||||
b -> 1 [1]
|
||||
a : 0 [0]
|
||||
[0] float parent=[0] [0:1)
|
||||
b : 1 [1]
|
||||
[0] string parent=[0] [0:1)
|
||||
[10] union[] parent=[0] [10:11)
|
||||
[0] union parent=[0] [0:1)
|
||||
x -> 0 [0]
|
||||
y -> 1 [1]
|
||||
x : 0 [0]
|
||||
[0] string parent=[0] [0:1)
|
||||
y : 1 [1]
|
||||
[0] string parent=[0] [0:1)
|
||||
)out")<<"Actual:\n"<<Value::Helper::desc(val);
|
||||
}
|
||||
|
||||
void testSerialize2()
|
||||
{
|
||||
testDiag("%s", __func__);
|
||||
@@ -344,6 +406,8 @@ void testDeserialize2()
|
||||
|
||||
void testTraverse()
|
||||
{
|
||||
testDiag("%s", __func__);
|
||||
|
||||
auto top = nt::NTScalar{TypeCode::Int32, true}.create();
|
||||
|
||||
testOk1(!top["<"].valid());
|
||||
@@ -361,16 +425,38 @@ void testTraverse()
|
||||
}
|
||||
}
|
||||
|
||||
void testAssign()
|
||||
{
|
||||
testDiag("%s", __func__);
|
||||
|
||||
auto def = nt::NTScalar{TypeCode::String}.build();
|
||||
auto val = def.create();
|
||||
|
||||
val["value"] = "Testing";
|
||||
val["timeStamp"].mark();
|
||||
val["alarm.severity"] = 3u;
|
||||
|
||||
auto val2 = val.cloneEmpty();
|
||||
|
||||
val2.assign(val);
|
||||
|
||||
testOk1(!val["alarm.status"].isMarked(true, true));
|
||||
testOk1(!!val["alarm"].isMarked(true, true));
|
||||
testOk1(!val["alarm"].isMarked(true, false));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MAIN(testdata)
|
||||
{
|
||||
testPlan(63);
|
||||
testPlan(67);
|
||||
testSerialize1();
|
||||
testDeserialize1();
|
||||
testSimpleDef();
|
||||
testSerialize2();
|
||||
testDeserialize2();
|
||||
testTraverse();
|
||||
testAssign();
|
||||
cleanup_for_valgrind();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
+55
-56
@@ -128,60 +128,60 @@ void testTypeDef()
|
||||
auto val = def.create();
|
||||
|
||||
testOk1(!!val.valid());
|
||||
testShow()<<Value::Helper::desc(val);
|
||||
testEq(std::string(SB()<<Value::Helper::desc(val)),
|
||||
"[0] struct simple_t <0:11> [0:18)\n"
|
||||
" achoice -> 14 [14]\n"
|
||||
" any -> 9 [9]\n"
|
||||
" anya -> 10 [10]\n"
|
||||
" arbitrary -> 5 [5]\n"
|
||||
" arbitrary.sarr -> 6 [6]\n"
|
||||
" choice -> 11 [11]\n"
|
||||
" timeStamp -> 2 [2]\n"
|
||||
" timeStamp.nanoseconds -> 4 [4]\n"
|
||||
" timeStamp.secondsPastEpoch -> 3 [3]\n"
|
||||
" value -> 1 [1]\n"
|
||||
" value : 1 [1]\n"
|
||||
" timeStamp : 2 [2]\n"
|
||||
" arbitrary : 5 [5]\n"
|
||||
" any : 9 [9]\n"
|
||||
" anya : 10 [10]\n"
|
||||
" choice : 11 [11]\n"
|
||||
" achoice : 14 [14]\n"
|
||||
"[1] double[] <1:2> [1:2)\n"
|
||||
"[2] struct time_t <2:3> [2:5)\n"
|
||||
" nanoseconds -> 2 [4]\n"
|
||||
" secondsPastEpoch -> 1 [3]\n"
|
||||
" secondsPastEpoch : 1 [3]\n"
|
||||
" nanoseconds : 2 [4]\n"
|
||||
"[3] uint64_t <3:4> [3:4)\n"
|
||||
"[4] uint32_t <4:5> [4:5)\n"
|
||||
"[5] struct <5:6> [5:9)\n"
|
||||
" sarr -> 1 [6]\n"
|
||||
" sarr : 1 [6]\n"
|
||||
"[6] struct[] <6:7> [6:9)\n"
|
||||
"[7] struct <0:2> [7:9)\n"
|
||||
" value -> 1 [8]\n"
|
||||
" value : 1 [8]\n"
|
||||
"[8] double <1:2> [8:9)\n"
|
||||
"[9] any <7:8> [9:10)\n"
|
||||
"[10] any[] <8:9> [10:11)\n"
|
||||
"[11] union <9:10> [11:14)\n"
|
||||
" a -> 1 [12]\n"
|
||||
" b -> 2 [13]\n"
|
||||
" a : 1 [12]\n"
|
||||
" b : 2 [13]\n"
|
||||
"[12] float <0:1> [12:13)\n"
|
||||
"[13] string <0:1> [13:14)\n"
|
||||
"[14] union[] <10:11> [14:18)\n"
|
||||
"[15] union <0:3> [15:18)\n"
|
||||
" x -> 1 [16]\n"
|
||||
" y -> 2 [17]\n"
|
||||
" x : 1 [16]\n"
|
||||
" y : 2 [17]\n"
|
||||
"[16] float <1:2> [16:17)\n"
|
||||
"[17] float <2:3> [17:18)\n"
|
||||
"");
|
||||
testEq(std::string(SB()<<"\n"<<Value::Helper::desc(val)),
|
||||
R"out(
|
||||
[0] struct simple_t parent=[0] [0:11)
|
||||
achoice -> 10 [10]
|
||||
any -> 7 [7]
|
||||
anya -> 8 [8]
|
||||
arbitrary -> 5 [5]
|
||||
arbitrary.sarr -> 6 [6]
|
||||
choice -> 9 [9]
|
||||
timeStamp -> 2 [2]
|
||||
timeStamp.nanoseconds -> 4 [4]
|
||||
timeStamp.secondsPastEpoch -> 3 [3]
|
||||
value -> 1 [1]
|
||||
value : 1 [1]
|
||||
timeStamp : 2 [2]
|
||||
arbitrary : 5 [5]
|
||||
any : 7 [7]
|
||||
anya : 8 [8]
|
||||
choice : 9 [9]
|
||||
achoice : 10 [10]
|
||||
[1] double[] parent=[0] [1:2)
|
||||
[2] struct time_t parent=[0] [2:5)
|
||||
nanoseconds -> 2 [4]
|
||||
secondsPastEpoch -> 1 [3]
|
||||
secondsPastEpoch : 1 [3]
|
||||
nanoseconds : 2 [4]
|
||||
[3] uint64_t parent=[2] [3:4)
|
||||
[4] uint32_t parent=[2] [4:5)
|
||||
[5] struct parent=[0] [5:7)
|
||||
sarr -> 1 [6]
|
||||
sarr : 1 [6]
|
||||
[6] struct[] parent=[5] [6:7)
|
||||
[0] struct parent=[0] [0:2)
|
||||
value -> 1 [1]
|
||||
value : 1 [1]
|
||||
[1] double parent=[0] [1:2)
|
||||
[7] any parent=[0] [7:8)
|
||||
[8] any[] parent=[0] [8:9)
|
||||
[9] union parent=[0] [9:10)
|
||||
a -> 0 [0]
|
||||
b -> 1 [1]
|
||||
a : 0 [0]
|
||||
[0] float parent=[0] [0:1)
|
||||
b : 1 [1]
|
||||
[0] string parent=[0] [0:1)
|
||||
[10] union[] parent=[0] [10:11)
|
||||
[0] union parent=[0] [0:1)
|
||||
x -> 0 [0]
|
||||
y -> 1 [1]
|
||||
x : 0 [0]
|
||||
[0] float parent=[0] [0:1)
|
||||
y : 1 [1]
|
||||
[0] float parent=[0] [0:1)
|
||||
)out")<<"Actual:\n"<<Value::Helper::desc(val);
|
||||
|
||||
// try to access all field Kinds
|
||||
|
||||
@@ -254,7 +254,6 @@ void testTypeDef()
|
||||
testEq(fld["[1]q"].as<std::string>(), "theq");
|
||||
}
|
||||
|
||||
testShow()<<val;
|
||||
testEq(std::string(SB()<<val),
|
||||
"struct \"simple_t\" {\n"
|
||||
" double[] value = {2}[1, 2]\n"
|
||||
@@ -287,7 +286,7 @@ void testTypeDef()
|
||||
" union.y float = 5\n"
|
||||
" null\n"
|
||||
" ]\n"
|
||||
"}\n");
|
||||
"}\n")<<"Actual:\n"<<val;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
+239
-243
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
* 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.
|
||||
@@ -54,10 +54,8 @@ void testDecode1()
|
||||
|
||||
{
|
||||
FixedBuf buf(true, msg);
|
||||
TypeDeserContext ctxt{descs, cache};
|
||||
from_wire(buf, ctxt);
|
||||
if(testOk1(buf.good()))
|
||||
FieldDesc_calculate_offset(descs.data());
|
||||
from_wire(buf, descs, cache);
|
||||
testOk1(buf.good());
|
||||
testEq(buf.size(), 0u)<<"Of "<<msg.size();
|
||||
}
|
||||
|
||||
@@ -75,17 +73,19 @@ void testDecode1()
|
||||
|
||||
// cat <<EOF | sed -e 's|"|\\"|g' -e 's|^# | "|' -e 's|$|\\n"|g'
|
||||
// paste in Actual
|
||||
testEq(std::string(SB()<<descs.data()),
|
||||
"[0] struct timeStamp_t <0:4> [0:4)\n"
|
||||
" nanoSeconds -> 2 [2]\n"
|
||||
" secondsPastEpoch -> 1 [1]\n"
|
||||
" userTag -> 3 [3]\n"
|
||||
" secondsPastEpoch : 1 [1]\n"
|
||||
" nanoSeconds : 2 [2]\n"
|
||||
" userTag : 3 [3]\n"
|
||||
"[1] int64_t <1:2> [1:2)\n"
|
||||
"[2] int32_t <2:3> [2:3)\n"
|
||||
"[3] int32_t <3:4> [3:4)\n"
|
||||
testEq(std::string(SB()<<"\n"<<descs.data()),
|
||||
R"out(
|
||||
[0] struct timeStamp_t parent=[0] [0:4)
|
||||
nanoSeconds -> 2 [2]
|
||||
secondsPastEpoch -> 1 [1]
|
||||
userTag -> 3 [3]
|
||||
secondsPastEpoch : 1 [1]
|
||||
nanoSeconds : 2 [2]
|
||||
userTag : 3 [3]
|
||||
[1] int64_t parent=[0] [1:2)
|
||||
[2] int32_t parent=[0] [2:3)
|
||||
[3] int32_t parent=[0] [3:4)
|
||||
)out"
|
||||
)<<"Actual:\n"<<descs.data();
|
||||
}
|
||||
|
||||
@@ -120,10 +120,8 @@ void testXCodeNTScalar()
|
||||
TypeStore cache;
|
||||
{
|
||||
FixedBuf buf(true, msg);
|
||||
TypeDeserContext ctxt{descs, cache};
|
||||
from_wire(buf, ctxt);
|
||||
if(testOk1(buf.good()))
|
||||
FieldDesc_calculate_offset(descs.data());
|
||||
from_wire(buf, descs, cache);
|
||||
testOk1(buf.good());
|
||||
testEq(buf.size(), 0u)<<"remaining of "<<msg.size();
|
||||
}
|
||||
|
||||
@@ -131,41 +129,43 @@ void testXCodeNTScalar()
|
||||
testEq(descs.size(), descs.front().size());
|
||||
}
|
||||
|
||||
testEq(std::string(SB()<<descs.data()),
|
||||
"[0] struct epics:nt/NTScalarArray:1.0 <0:10> [0:10)\n"
|
||||
" alarm -> 2 [2]\n"
|
||||
" alarm.message -> 5 [5]\n"
|
||||
" alarm.severity -> 3 [3]\n"
|
||||
" alarm.status -> 4 [4]\n"
|
||||
" timeStamp -> 6 [6]\n"
|
||||
" timeStamp.nanoseconds -> 8 [8]\n"
|
||||
" timeStamp.secondsPastEpoch -> 7 [7]\n"
|
||||
" timeStamp.userTag -> 9 [9]\n"
|
||||
" value -> 1 [1]\n"
|
||||
" value : 1 [1]\n"
|
||||
" alarm : 2 [2]\n"
|
||||
" timeStamp : 6 [6]\n"
|
||||
"[1] double[] <1:2> [1:2)\n"
|
||||
"[2] struct alarm_t <2:3> [2:6)\n"
|
||||
" message -> 3 [5]\n"
|
||||
" severity -> 1 [3]\n"
|
||||
" status -> 2 [4]\n"
|
||||
" severity : 1 [3]\n"
|
||||
" status : 2 [4]\n"
|
||||
" message : 3 [5]\n"
|
||||
"[3] int32_t <3:4> [3:4)\n"
|
||||
"[4] int32_t <4:5> [4:5)\n"
|
||||
"[5] string <5:6> [5:6)\n"
|
||||
"[6] struct time_t <6:7> [6:10)\n"
|
||||
" nanoseconds -> 2 [8]\n"
|
||||
" secondsPastEpoch -> 1 [7]\n"
|
||||
" userTag -> 3 [9]\n"
|
||||
" secondsPastEpoch : 1 [7]\n"
|
||||
" nanoseconds : 2 [8]\n"
|
||||
" userTag : 3 [9]\n"
|
||||
"[7] int64_t <7:8> [7:8)\n"
|
||||
"[8] int32_t <8:9> [8:9)\n"
|
||||
"[9] int32_t <9:10> [9:10)\n"
|
||||
testEq(std::string(SB()<<"\n"<<descs.data()),
|
||||
R"out(
|
||||
[0] struct epics:nt/NTScalarArray:1.0 parent=[0] [0:10)
|
||||
alarm -> 2 [2]
|
||||
alarm.message -> 5 [5]
|
||||
alarm.severity -> 3 [3]
|
||||
alarm.status -> 4 [4]
|
||||
timeStamp -> 6 [6]
|
||||
timeStamp.nanoseconds -> 8 [8]
|
||||
timeStamp.secondsPastEpoch -> 7 [7]
|
||||
timeStamp.userTag -> 9 [9]
|
||||
value -> 1 [1]
|
||||
value : 1 [1]
|
||||
alarm : 2 [2]
|
||||
timeStamp : 6 [6]
|
||||
[1] double[] parent=[0] [1:2)
|
||||
[2] struct alarm_t parent=[0] [2:6)
|
||||
message -> 3 [5]
|
||||
severity -> 1 [3]
|
||||
status -> 2 [4]
|
||||
severity : 1 [3]
|
||||
status : 2 [4]
|
||||
message : 3 [5]
|
||||
[3] int32_t parent=[2] [3:4)
|
||||
[4] int32_t parent=[2] [4:5)
|
||||
[5] string parent=[2] [5:6)
|
||||
[6] struct time_t parent=[0] [6:10)
|
||||
nanoseconds -> 2 [8]
|
||||
secondsPastEpoch -> 1 [7]
|
||||
userTag -> 3 [9]
|
||||
secondsPastEpoch : 1 [7]
|
||||
nanoseconds : 2 [8]
|
||||
userTag : 3 [9]
|
||||
[7] int64_t parent=[6] [7:8)
|
||||
[8] int32_t parent=[6] [8:9)
|
||||
[9] int32_t parent=[6] [9:10)
|
||||
)out"
|
||||
)<<"Actual:\n"<<descs.data();
|
||||
|
||||
testDiag("Round trip back to bytes");
|
||||
@@ -246,10 +246,8 @@ void testXCodeNTNDArray()
|
||||
TypeStore cache;
|
||||
{
|
||||
FixedBuf buf(true, msg);
|
||||
TypeDeserContext ctxt{descs, cache};
|
||||
from_wire(buf, ctxt);
|
||||
if(testOk1(buf.good()))
|
||||
FieldDesc_calculate_offset(descs.data());
|
||||
from_wire(buf, descs, cache);
|
||||
testOk1(buf.good());
|
||||
testEq(buf.size(), 0u)<<"remaining of "<<msg.size();
|
||||
}
|
||||
|
||||
@@ -257,180 +255,182 @@ void testXCodeNTNDArray()
|
||||
testEq(descs.size(), descs.front().size());
|
||||
}
|
||||
|
||||
testEq(std::string(SB()<<descs.data()),
|
||||
"[0] struct epics:nt/NTNDArray:1.0 <0:22> [0:54)\n"
|
||||
" alarm -> 23 [23]\n"
|
||||
" alarm.message -> 26 [26]\n"
|
||||
" alarm.severity -> 24 [24]\n"
|
||||
" alarm.status -> 25 [25]\n"
|
||||
" attribute -> 38 [38]\n"
|
||||
" codec -> 13 [13]\n"
|
||||
" codec.name -> 14 [14]\n"
|
||||
" codec.parameters -> 15 [15]\n"
|
||||
" compressedSize -> 16 [16]\n"
|
||||
" dataTimeStamp -> 19 [19]\n"
|
||||
" dataTimeStamp.nanoseconds -> 21 [21]\n"
|
||||
" dataTimeStamp.secondsPastEpoch -> 20 [20]\n"
|
||||
" dataTimeStamp.userTag -> 22 [22]\n"
|
||||
" dimension -> 31 [31]\n"
|
||||
" timeStamp -> 27 [27]\n"
|
||||
" timeStamp.nanoseconds -> 29 [29]\n"
|
||||
" timeStamp.secondsPastEpoch -> 28 [28]\n"
|
||||
" timeStamp.userTag -> 30 [30]\n"
|
||||
" uncompressedSize -> 17 [17]\n"
|
||||
" uniqueId -> 18 [18]\n"
|
||||
" value -> 1 [1]\n"
|
||||
" value : 1 [1]\n"
|
||||
" codec : 13 [13]\n"
|
||||
" compressedSize : 16 [16]\n"
|
||||
" uncompressedSize : 17 [17]\n"
|
||||
" uniqueId : 18 [18]\n"
|
||||
" dataTimeStamp : 19 [19]\n"
|
||||
" alarm : 23 [23]\n"
|
||||
" timeStamp : 27 [27]\n"
|
||||
" dimension : 31 [31]\n"
|
||||
" attribute : 38 [38]\n"
|
||||
"[1] union <1:2> [1:13)\n"
|
||||
" booleanValue -> 1 [2]\n"
|
||||
" byteValue -> 2 [3]\n"
|
||||
" doubleValue -> 11 [12]\n"
|
||||
" floatValue -> 10 [11]\n"
|
||||
" intValue -> 4 [5]\n"
|
||||
" longValue -> 5 [6]\n"
|
||||
" shortValue -> 3 [4]\n"
|
||||
" ubyteValue -> 6 [7]\n"
|
||||
" uintValue -> 8 [9]\n"
|
||||
" ulongValue -> 9 [10]\n"
|
||||
" ushortValue -> 7 [8]\n"
|
||||
" booleanValue : 1 [2]\n"
|
||||
" byteValue : 2 [3]\n"
|
||||
" shortValue : 3 [4]\n"
|
||||
" intValue : 4 [5]\n"
|
||||
" longValue : 5 [6]\n"
|
||||
" ubyteValue : 6 [7]\n"
|
||||
" ushortValue : 7 [8]\n"
|
||||
" uintValue : 8 [9]\n"
|
||||
" ulongValue : 9 [10]\n"
|
||||
" floatValue : 10 [11]\n"
|
||||
" doubleValue : 11 [12]\n"
|
||||
"[2] bool[] <0:1> [2:3)\n"
|
||||
"[3] int8_t[] <0:1> [3:4)\n"
|
||||
"[4] int16_t[] <0:1> [4:5)\n"
|
||||
"[5] int32_t[] <0:1> [5:6)\n"
|
||||
"[6] int64_t[] <0:1> [6:7)\n"
|
||||
"[7] uint8_t[] <0:1> [7:8)\n"
|
||||
"[8] uint16_t[] <0:1> [8:9)\n"
|
||||
"[9] uint32_t[] <0:1> [9:10)\n"
|
||||
"[10] uint64_t[] <0:1> [10:11)\n"
|
||||
"[11] float[] <0:1> [11:12)\n"
|
||||
"[12] double[] <0:1> [12:13)\n"
|
||||
"[13] struct codec_t <2:3> [13:16)\n"
|
||||
" name -> 1 [14]\n"
|
||||
" parameters -> 2 [15]\n"
|
||||
" name : 1 [14]\n"
|
||||
" parameters : 2 [15]\n"
|
||||
"[14] string <3:4> [14:15)\n"
|
||||
"[15] any <4:5> [15:16)\n"
|
||||
"[16] int64_t <5:6> [16:17)\n"
|
||||
"[17] int64_t <6:7> [17:18)\n"
|
||||
"[18] int32_t <7:8> [18:19)\n"
|
||||
"[19] struct time_t <8:9> [19:23)\n"
|
||||
" nanoseconds -> 2 [21]\n"
|
||||
" secondsPastEpoch -> 1 [20]\n"
|
||||
" userTag -> 3 [22]\n"
|
||||
" secondsPastEpoch : 1 [20]\n"
|
||||
" nanoseconds : 2 [21]\n"
|
||||
" userTag : 3 [22]\n"
|
||||
"[20] int64_t <9:10> [20:21)\n"
|
||||
"[21] int32_t <10:11> [21:22)\n"
|
||||
"[22] int32_t <11:12> [22:23)\n"
|
||||
"[23] struct alarm_t <12:13> [23:27)\n"
|
||||
" message -> 3 [26]\n"
|
||||
" severity -> 1 [24]\n"
|
||||
" status -> 2 [25]\n"
|
||||
" severity : 1 [24]\n"
|
||||
" status : 2 [25]\n"
|
||||
" message : 3 [26]\n"
|
||||
"[24] int32_t <13:14> [24:25)\n"
|
||||
"[25] int32_t <14:15> [25:26)\n"
|
||||
"[26] string <15:16> [26:27)\n"
|
||||
"[27] struct time_t <16:17> [27:31)\n"
|
||||
" nanoseconds -> 2 [29]\n"
|
||||
" secondsPastEpoch -> 1 [28]\n"
|
||||
" userTag -> 3 [30]\n"
|
||||
" secondsPastEpoch : 1 [28]\n"
|
||||
" nanoseconds : 2 [29]\n"
|
||||
" userTag : 3 [30]\n"
|
||||
"[28] int64_t <17:18> [28:29)\n"
|
||||
"[29] int32_t <18:19> [29:30)\n"
|
||||
"[30] int32_t <19:20> [30:31)\n"
|
||||
"[31] struct[] <20:21> [31:38)\n"
|
||||
"[32] struct dimension_t <0:6> [32:38)\n"
|
||||
" binning -> 4 [36]\n"
|
||||
" fullSize -> 3 [35]\n"
|
||||
" offset -> 2 [34]\n"
|
||||
" reverse -> 5 [37]\n"
|
||||
" size -> 1 [33]\n"
|
||||
" size : 1 [33]\n"
|
||||
" offset : 2 [34]\n"
|
||||
" fullSize : 3 [35]\n"
|
||||
" binning : 4 [36]\n"
|
||||
" reverse : 5 [37]\n"
|
||||
"[33] int32_t <1:2> [33:34)\n"
|
||||
"[34] int32_t <2:3> [34:35)\n"
|
||||
"[35] int32_t <3:4> [35:36)\n"
|
||||
"[36] int32_t <4:5> [36:37)\n"
|
||||
"[37] bool <5:6> [37:38)\n"
|
||||
"[38] struct[] <21:22> [38:54)\n"
|
||||
"[39] struct epics:nt/NTAttribute:1.0 <0:15> [39:54)\n"
|
||||
" alarm -> 5 [44]\n"
|
||||
" alarm.message -> 47 [86]\n"
|
||||
" alarm.severity -> 45 [84]\n"
|
||||
" alarm.status -> 46 [85]\n"
|
||||
" descriptor -> 4 [43]\n"
|
||||
" name -> 1 [40]\n"
|
||||
" source -> 14 [53]\n"
|
||||
" sourceType -> 13 [52]\n"
|
||||
" tags -> 3 [42]\n"
|
||||
" timestamp -> 9 [48]\n"
|
||||
" timestamp.nanoseconds -> 50 [89]\n"
|
||||
" timestamp.secondsPastEpoch -> 49 [88]\n"
|
||||
" timestamp.userTag -> 51 [90]\n"
|
||||
" value -> 2 [41]\n"
|
||||
" name : 1 [40]\n"
|
||||
" value : 2 [41]\n"
|
||||
" tags : 3 [42]\n"
|
||||
" descriptor : 4 [43]\n"
|
||||
" alarm : 5 [44]\n"
|
||||
" timestamp : 9 [48]\n"
|
||||
" sourceType : 13 [52]\n"
|
||||
" source : 14 [53]\n"
|
||||
"[40] string <1:2> [40:41)\n"
|
||||
"[41] any <2:3> [41:42)\n"
|
||||
"[42] string[] <3:4> [42:43)\n"
|
||||
"[43] string <4:5> [43:44)\n"
|
||||
"[44] struct alarm_t <5:6> [44:48)\n"
|
||||
" message -> 3 [47]\n"
|
||||
" severity -> 1 [45]\n"
|
||||
" status -> 2 [46]\n"
|
||||
" severity : 1 [45]\n"
|
||||
" status : 2 [46]\n"
|
||||
" message : 3 [47]\n"
|
||||
"[45] int32_t <6:7> [45:46)\n"
|
||||
"[46] int32_t <7:8> [46:47)\n"
|
||||
"[47] string <8:9> [47:48)\n"
|
||||
"[48] struct time_t <9:10> [48:52)\n"
|
||||
" nanoseconds -> 2 [50]\n"
|
||||
" secondsPastEpoch -> 1 [49]\n"
|
||||
" userTag -> 3 [51]\n"
|
||||
" secondsPastEpoch : 1 [49]\n"
|
||||
" nanoseconds : 2 [50]\n"
|
||||
" userTag : 3 [51]\n"
|
||||
"[49] int64_t <10:11> [49:50)\n"
|
||||
"[50] int32_t <11:12> [50:51)\n"
|
||||
"[51] int32_t <12:13> [51:52)\n"
|
||||
"[52] int32_t <13:14> [52:53)\n"
|
||||
"[53] string <14:15> [53:54)\n"
|
||||
testEq(std::string(SB()<<"\n"<<descs.data()),
|
||||
R"out(
|
||||
[0] struct epics:nt/NTNDArray:1.0 parent=[0] [0:22)
|
||||
alarm -> 12 [12]
|
||||
alarm.message -> 15 [15]
|
||||
alarm.severity -> 13 [13]
|
||||
alarm.status -> 14 [14]
|
||||
attribute -> 21 [21]
|
||||
codec -> 2 [2]
|
||||
codec.name -> 3 [3]
|
||||
codec.parameters -> 4 [4]
|
||||
compressedSize -> 5 [5]
|
||||
dataTimeStamp -> 8 [8]
|
||||
dataTimeStamp.nanoseconds -> 10 [10]
|
||||
dataTimeStamp.secondsPastEpoch -> 9 [9]
|
||||
dataTimeStamp.userTag -> 11 [11]
|
||||
dimension -> 20 [20]
|
||||
timeStamp -> 16 [16]
|
||||
timeStamp.nanoseconds -> 18 [18]
|
||||
timeStamp.secondsPastEpoch -> 17 [17]
|
||||
timeStamp.userTag -> 19 [19]
|
||||
uncompressedSize -> 6 [6]
|
||||
uniqueId -> 7 [7]
|
||||
value -> 1 [1]
|
||||
value : 1 [1]
|
||||
codec : 2 [2]
|
||||
compressedSize : 5 [5]
|
||||
uncompressedSize : 6 [6]
|
||||
uniqueId : 7 [7]
|
||||
dataTimeStamp : 8 [8]
|
||||
alarm : 12 [12]
|
||||
timeStamp : 16 [16]
|
||||
dimension : 20 [20]
|
||||
attribute : 21 [21]
|
||||
[1] union parent=[0] [1:2)
|
||||
booleanValue -> 0 [0]
|
||||
byteValue -> 1 [1]
|
||||
doubleValue -> 10 [10]
|
||||
floatValue -> 9 [9]
|
||||
intValue -> 3 [3]
|
||||
longValue -> 4 [4]
|
||||
shortValue -> 2 [2]
|
||||
ubyteValue -> 5 [5]
|
||||
uintValue -> 7 [7]
|
||||
ulongValue -> 8 [8]
|
||||
ushortValue -> 6 [6]
|
||||
booleanValue : 0 [0]
|
||||
[0] bool[] parent=[0] [0:1)
|
||||
byteValue : 1 [1]
|
||||
[0] int8_t[] parent=[0] [0:1)
|
||||
shortValue : 2 [2]
|
||||
[0] int16_t[] parent=[0] [0:1)
|
||||
intValue : 3 [3]
|
||||
[0] int32_t[] parent=[0] [0:1)
|
||||
longValue : 4 [4]
|
||||
[0] int64_t[] parent=[0] [0:1)
|
||||
ubyteValue : 5 [5]
|
||||
[0] uint8_t[] parent=[0] [0:1)
|
||||
ushortValue : 6 [6]
|
||||
[0] uint16_t[] parent=[0] [0:1)
|
||||
uintValue : 7 [7]
|
||||
[0] uint32_t[] parent=[0] [0:1)
|
||||
ulongValue : 8 [8]
|
||||
[0] uint64_t[] parent=[0] [0:1)
|
||||
floatValue : 9 [9]
|
||||
[0] float[] parent=[0] [0:1)
|
||||
doubleValue : 10 [10]
|
||||
[0] double[] parent=[0] [0:1)
|
||||
[2] struct codec_t parent=[0] [2:5)
|
||||
name -> 1 [3]
|
||||
parameters -> 2 [4]
|
||||
name : 1 [3]
|
||||
parameters : 2 [4]
|
||||
[3] string parent=[2] [3:4)
|
||||
[4] any parent=[2] [4:5)
|
||||
[5] int64_t parent=[0] [5:6)
|
||||
[6] int64_t parent=[0] [6:7)
|
||||
[7] int32_t parent=[0] [7:8)
|
||||
[8] struct time_t parent=[0] [8:12)
|
||||
nanoseconds -> 2 [10]
|
||||
secondsPastEpoch -> 1 [9]
|
||||
userTag -> 3 [11]
|
||||
secondsPastEpoch : 1 [9]
|
||||
nanoseconds : 2 [10]
|
||||
userTag : 3 [11]
|
||||
[9] int64_t parent=[8] [9:10)
|
||||
[10] int32_t parent=[8] [10:11)
|
||||
[11] int32_t parent=[8] [11:12)
|
||||
[12] struct alarm_t parent=[0] [12:16)
|
||||
message -> 3 [15]
|
||||
severity -> 1 [13]
|
||||
status -> 2 [14]
|
||||
severity : 1 [13]
|
||||
status : 2 [14]
|
||||
message : 3 [15]
|
||||
[13] int32_t parent=[12] [13:14)
|
||||
[14] int32_t parent=[12] [14:15)
|
||||
[15] string parent=[12] [15:16)
|
||||
[16] struct time_t parent=[0] [16:20)
|
||||
nanoseconds -> 2 [18]
|
||||
secondsPastEpoch -> 1 [17]
|
||||
userTag -> 3 [19]
|
||||
secondsPastEpoch : 1 [17]
|
||||
nanoseconds : 2 [18]
|
||||
userTag : 3 [19]
|
||||
[17] int64_t parent=[16] [17:18)
|
||||
[18] int32_t parent=[16] [18:19)
|
||||
[19] int32_t parent=[16] [19:20)
|
||||
[20] struct[] parent=[0] [20:21)
|
||||
[0] struct dimension_t parent=[0] [0:6)
|
||||
binning -> 4 [4]
|
||||
fullSize -> 3 [3]
|
||||
offset -> 2 [2]
|
||||
reverse -> 5 [5]
|
||||
size -> 1 [1]
|
||||
size : 1 [1]
|
||||
offset : 2 [2]
|
||||
fullSize : 3 [3]
|
||||
binning : 4 [4]
|
||||
reverse : 5 [5]
|
||||
[1] int32_t parent=[0] [1:2)
|
||||
[2] int32_t parent=[0] [2:3)
|
||||
[3] int32_t parent=[0] [3:4)
|
||||
[4] int32_t parent=[0] [4:5)
|
||||
[5] bool parent=[0] [5:6)
|
||||
[21] struct[] parent=[0] [21:22)
|
||||
[0] struct epics:nt/NTAttribute:1.0 parent=[0] [0:15)
|
||||
alarm -> 5 [5]
|
||||
alarm.message -> 8 [8]
|
||||
alarm.severity -> 6 [6]
|
||||
alarm.status -> 7 [7]
|
||||
descriptor -> 4 [4]
|
||||
name -> 1 [1]
|
||||
source -> 14 [14]
|
||||
sourceType -> 13 [13]
|
||||
tags -> 3 [3]
|
||||
timestamp -> 9 [9]
|
||||
timestamp.nanoseconds -> 11 [11]
|
||||
timestamp.secondsPastEpoch -> 10 [10]
|
||||
timestamp.userTag -> 12 [12]
|
||||
value -> 2 [2]
|
||||
name : 1 [1]
|
||||
value : 2 [2]
|
||||
tags : 3 [3]
|
||||
descriptor : 4 [4]
|
||||
alarm : 5 [5]
|
||||
timestamp : 9 [9]
|
||||
sourceType : 13 [13]
|
||||
source : 14 [14]
|
||||
[1] string parent=[0] [1:2)
|
||||
[2] any parent=[0] [2:3)
|
||||
[3] string[] parent=[0] [3:4)
|
||||
[4] string parent=[0] [4:5)
|
||||
[5] struct alarm_t parent=[0] [5:9)
|
||||
message -> 3 [8]
|
||||
severity -> 1 [6]
|
||||
status -> 2 [7]
|
||||
severity : 1 [6]
|
||||
status : 2 [7]
|
||||
message : 3 [8]
|
||||
[6] int32_t parent=[5] [6:7)
|
||||
[7] int32_t parent=[5] [7:8)
|
||||
[8] string parent=[5] [8:9)
|
||||
[9] struct time_t parent=[0] [9:13)
|
||||
nanoseconds -> 2 [11]
|
||||
secondsPastEpoch -> 1 [10]
|
||||
userTag -> 3 [12]
|
||||
secondsPastEpoch : 1 [10]
|
||||
nanoseconds : 2 [11]
|
||||
userTag : 3 [12]
|
||||
[10] int64_t parent=[9] [10:11)
|
||||
[11] int32_t parent=[9] [11:12)
|
||||
[12] int32_t parent=[9] [12:13)
|
||||
[13] int32_t parent=[0] [13:14)
|
||||
[14] string parent=[0] [14:15)
|
||||
)out"
|
||||
)<<"Actual:\n"<<descs.data();
|
||||
|
||||
testDiag("Round trip back to bytes");
|
||||
@@ -459,10 +459,8 @@ void testEmptyRequest()
|
||||
{
|
||||
uint8_t msg[] = "\xfd\x02\x00\x80\x00\x00";
|
||||
FixedBuf buf(false, msg);
|
||||
TypeDeserContext ctxt{descs1, registry};
|
||||
from_wire(buf, ctxt);
|
||||
if(testOk1(buf.good()))
|
||||
FieldDesc_calculate_offset(descs1.data());
|
||||
from_wire(buf, descs1, registry);
|
||||
testOk1(buf.good());
|
||||
testEq(buf.size(), 0u)<<"remaining of "<<sizeof(msg-1);
|
||||
}
|
||||
|
||||
@@ -474,10 +472,8 @@ void testEmptyRequest()
|
||||
{
|
||||
uint8_t msg[] = "\xfe\x02\x00";
|
||||
FixedBuf buf(false, msg);
|
||||
TypeDeserContext ctxt{descs2, registry};
|
||||
from_wire(buf, ctxt);
|
||||
if(testOk1(buf.good()))
|
||||
FieldDesc_calculate_offset(descs2.data());
|
||||
from_wire(buf, descs2, registry);
|
||||
testOk1(buf.good());
|
||||
testEq(buf.size(), 0u)<<"remaining of "<<sizeof(msg-1);
|
||||
}
|
||||
|
||||
@@ -485,10 +481,10 @@ void testEmptyRequest()
|
||||
testEq(descs2.size(), 1u);
|
||||
|
||||
testEq(std::string(SB()<<descs1.data()),
|
||||
"[0] struct <0:1> [0:1)\n")<<"\nActual descs1\n"<<descs1.data();
|
||||
"[0] struct parent=[0] [0:1)\n")<<"\nActual descs1\n"<<descs1.data();
|
||||
|
||||
testEq(std::string(SB()<<descs2.data()),
|
||||
"[0] struct <0:1> [0:1)\n")<<"\nActual descs2\n"<<descs2.data();
|
||||
"[0] struct parent=[0] [0:1)\n")<<"\nActual descs2\n"<<descs2.data();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user