diff --git a/src/data.cpp b/src/data.cpp index 8754da0..8400811 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -855,61 +855,67 @@ void Value::traverse(const std::string &expr, bool modify, bool dothrow) // attempt to traverse to (and maybe select) member // expect: ->[0-9a-zA-Z_]+[.\[-$] - maybedot = false; - if(expr.size()-pos >= 2 && expr[pos]=='-' && expr[pos+1]=='>') { pos += 2; // skip past "->" - if(desc->code.code==TypeCode::Any) { - // select member of Any (may be Null) - *this = store->as(); - - } else { - // select member of Union - size_t sep = expr.find_first_of("<[-.", pos); - - decltype (desc->mlookup)::const_iterator it; - auto& fld = store->as(); - - if(sep>0 && (it=desc->mlookup.find(expr.substr(pos, sep-pos)))!=desc->mlookup.end()) { - // found it. - - if(modify || fld.desc==&desc->members[it->second]) { - // will select, or already selected - if(fld.desc!=&desc->members[it->second]) { - // select - std::shared_ptr mtype(store->top->desc, &desc->members[it->second]); - fld = Value(mtype, *this); - } - pos = sep; - *this = fld; - maybedot = true; - - } else { - // traversing const Value, can't select Union - store.reset(); - desc = nullptr; - if(dothrow) - throw LookupError(SB()<<"traversing const Value, can't select Union in '"<0u || desc->code.code!=TypeCode::Union) { // expected "->" + // allow omission at the beginning of an expression when starting from a Union store.reset(); desc = nullptr; if(dothrow) throw LookupError(SB()<<"expected -> in '"<" when pos==0 + } + + maybedot = false; + + if(desc->code.code==TypeCode::Any) { + // select member of Any (may be Null) + *this = store->as(); + + } else { + // select member of Union + size_t sep = expr.find_first_of("<[-.", pos); + + decltype (desc->mlookup)::const_iterator it; + auto& fld = store->as(); + + if(sep>0 && (it=desc->mlookup.find(expr.substr(pos, sep-pos)))!=desc->mlookup.end()) { + // found it. + + if(modify || fld.desc==&desc->members[it->second]) { + // will select, or already selected + if(fld.desc!=&desc->members[it->second]) { + // select + std::shared_ptr mtype(store->top->desc, &desc->members[it->second]); + fld = Value(mtype, *this); + } + pos = sep; + *this = fld; + maybedot = true; + + } else { + // traversing const Value, can't select Union + store.reset(); + desc = nullptr; + if(dothrow) + throw LookupError(SB()<<"traversing const Value, can't select Union in '"<code.isarray() && desc->code.kind()==Kind::Compound) { diff --git a/src/pvxs/data.h b/src/pvxs/data.h index 1affdeb..9b9d368 100644 --- a/src/pvxs/data.h +++ b/src/pvxs/data.h @@ -721,6 +721,10 @@ public: * * "dimension[0]size" * * "value->booleanValue" * + * @since UNRELEASED A leading "->" may be omitted when indirecting + * into a Union. eg. "->booleanValue" may be replaced with + * "booleanValue". + * * @returns A valid() Value if the descendant field exists, otherwise an invalid Value. */ Value operator[](const std::string& name); diff --git a/test/testdata.cpp b/test/testdata.cpp index 773450c..4214e0a 100644 --- a/test/testdata.cpp +++ b/test/testdata.cpp @@ -94,6 +94,8 @@ void testAssignUnion() val["->u16"] = 42; testEq(val.as(), "42"); + val["u16"] = 43; + testEq(val.as(), 43); val["->s"] = "test"; testEq(val.as(), "test"); @@ -562,7 +564,7 @@ void test_cache_sync() MAIN(testdata) { - testPlan(195); + testPlan(196); testSetup(); testTraverse(); testAssign();