diff --git a/src/data.cpp b/src/data.cpp index 19629e7..5e573f4 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -149,150 +149,17 @@ Value Value::clone() const return ret; } -static -bool assignCompatible(const FieldDesc* tdesc, - const FieldStorage* tstore, - const FieldDesc* sdesc, - const FieldStorage* sstore) -{ - if(tdesc==sdesc) { - // exact match - return true; - - } else if(!sdesc) { - // assignment of NULL is always a noop - return true; - - // from this point we know tdesc!=NULL - - } else if(tdesc->code.storedAs()!=sdesc->code.storedAs()) { - // TODO kind conversion? - return false; - } - - switch (tdesc->code.storedAs()) { - case StoreType::Bool: - case StoreType::Real: - case StoreType::String: - case StoreType::Integer: - case StoreType::UInteger: - // simple scalar field - return true; - case StoreType::Null: - // Structure assignment allowed if src has all target fields (extras ignored) - for(size_t idx : range(size_t(1u), tdesc->size())) { - auto it = sdesc->mlookup.find(tdesc->miter[idx-1u].first); - if(it==sdesc->mlookup.end()) { - return false; - } - auto schild = sdesc + it->second; - auto tchild = tdesc + idx; - - if(!assignCompatible(tchild, tstore+idx, schild, sstore+it->second)) - return false; - } - return true; - case StoreType::Array: - if(tdesc->code!=sdesc->code) { - // TODO array type conversion? - return false; - } else if((tdesc->code.kind()==Kind::Bool) - || (tdesc->code.kind()==Kind::Real) - || (tdesc->code.kind()==Kind::String) - || (tdesc->code.kind()==Kind::Integer) - || tdesc->code==TypeCode::AnyA) { - return true; - } else { - // TODO StructS, UnionS - return false; - } - break; - case StoreType::Compound: - // not implemented (yet?) - return false; - } - - return false; -} - Value& Value::assign(const Value& o) { - if(!assignCompatible(desc, store.get(), - o.desc, o.store.get())) - throw std::runtime_error("assign() not supported for these types"); + if(!store || !o.store) + throw std::logic_error("Can't assign() to/from empty Value"); - if(desc && o.desc) { - for(size_t bit=0, end=desc->size(); bitvalid) { - bit++; - continue; - } - - dstore->valid = true; - - switch(dstore->code) { - case StoreType::Real: - case StoreType::Bool: - case StoreType::Integer: - case StoreType::UInteger: - dstore->as() = sstore->as(); - bit++; - break; - case StoreType::String: - dstore->as() = sstore->as(); - bit++; - break; - case StoreType::Array: - dstore->as>() = sstore->as>(); - bit++; - break; - case StoreType::Compound: - dstore->as() = sstore->as(); - bit++; - break; - case StoreType::Null: { - // copy entire sub-structure - auto sdesc = desc + bit; - - for(auto end2 = bit + sdesc->size(); bitvalid = true; - - switch(dstore->code) { - case StoreType::Real: - case StoreType::Bool: - case StoreType::Integer: - case StoreType::UInteger: - dstore->as() = sstore->as(); - bit++; - break; - case StoreType::String: - dstore->as() = sstore->as(); - bit++; - break; - case StoreType::Array: - dstore->as>() = sstore->as>(); - bit++; - break; - case StoreType::Compound: - dstore->as() = sstore->as(); - bit++; - break; - case StoreType::Null: // skip sub-struct nodes, we will copy all leaf nodes - break; - } - - } - } - break; - } - } + if(type().kind()==Kind::Compound) { + // pass through Struct and others w/ type + copyIn(&o, StoreType::Compound); + } else { + // unpack other field types + copyIn(o.store.get(), o.store->code); } return *this; } @@ -703,15 +570,10 @@ void Value::copyIn(const void *ptr, StoreType type) for(auto& sfld : src.imarked()) { if(sfld.type()==TypeCode::Struct) { - // entire sub-struct marked + // entire sub-struct marked. - for(auto& sfld2 : sfld.iall()) { - - if(auto dfld = (*this)[src.nameOf(sfld2)]) { - dfld.copyIn(&sfld2.store->store, sfld2.store->code); - } else { - throw NoField(); - } + if(auto dfld = (*this)[src.nameOf(sfld)]) { + dfld.mark(); } } else { @@ -722,6 +584,10 @@ void Value::copyIn(const void *ptr, StoreType type) } } } + if(src.isMarked()) + mark(); + + return; } } throw NoConvert(); diff --git a/src/pvxs/data.h b/src/pvxs/data.h index 8ab70a0..b94dcee 100644 --- a/src/pvxs/data.h +++ b/src/pvxs/data.h @@ -494,8 +494,10 @@ public: Value cloneEmpty() const; //! allocate new storage and copy in our values Value clone() const; - //! copy values from other. Must have matching types. - Value& assign(const Value&); + //! copy value(s) from other. + //! Acts like from(o) for kind==Kind::Compound . + //! Acts like from(o.as()) for kind!=Kind::Compound + Value& assign(const Value& o); //! Use to allocate members for an array of Struct and array of Union Value allocMember(); diff --git a/test/testdata.cpp b/test/testdata.cpp index e6963ce..a94cc2e 100644 --- a/test/testdata.cpp +++ b/test/testdata.cpp @@ -192,11 +192,76 @@ void testConvertScalar(const Store& store, const Inout& inout) testEq(inout, cont.as())<"<(), 4.0); + + val1.unmark(); + + val2["display.description"] = "blah"; + + testThrows([&val1, &val2]() { + val1.assign(val2); + }); + } +} + } // namespace MAIN(testdata) { - testPlan(62); + testPlan(78); testTraverse(); testAssign(); testName(); @@ -223,6 +288,7 @@ MAIN(testdata) testConvertScalar("-5", -5); testConvertScalar("-5", -5.0); testConvertScalar("-5", "-5"); + testAssignSimilar(); cleanup_for_valgrind(); return testDone(); }