diff --git a/src/factory/FieldCreateFactory.cpp b/src/factory/FieldCreateFactory.cpp index a978c56..092e88b 100644 --- a/src/factory/FieldCreateFactory.cpp +++ b/src/factory/FieldCreateFactory.cpp @@ -701,18 +701,52 @@ void Union::deserialize(ByteBuffer* /*buffer*/, DeserializableControl* /*control throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead"); } +FieldBuilder::FieldBuilder() + :fieldCreate(getFieldCreate()) + ,idSet(false) + ,nestedClassToBuild(structure) + ,nestedArray(false) + ,createNested(true) +{} -FieldBuilder::FieldBuilder() : fieldCreate(getFieldCreate()), idSet(false) {} +FieldBuilder::FieldBuilder(const Structure* S) + :fieldCreate(getFieldCreate()) + ,id(S->getID()) + ,idSet(!id.empty()) + ,fieldNames(S->getFieldNames()) + ,fields(S->getFields()) + ,parentBuilder() + ,nestedClassToBuild(structure) + ,nestedName() + ,nestedArray(false) + ,createNested(false) +{} + +FieldBuilder::FieldBuilder(const FieldBuilderPtr & _parentBuilder, + const std::string& name, + const Structure* S) + :fieldCreate(_parentBuilder->fieldCreate) + ,id(S->getID()) + ,idSet(!id.empty()) + ,fieldNames(S->getFieldNames()) + ,fields(S->getFields()) + ,parentBuilder(_parentBuilder) + ,nestedClassToBuild(structure) + ,nestedName(name) + ,nestedArray(false) + ,createNested(false) +{} FieldBuilder::FieldBuilder(FieldBuilderPtr const & _parentBuilder, string const & _nestedName, - Type _nestedClassToBuild, bool _nestedArray) : - fieldCreate(getFieldCreate()), - idSet(false), - parentBuilder(_parentBuilder), - nestedClassToBuild(_nestedClassToBuild), - nestedName(_nestedName), - nestedArray(_nestedArray) + Type _nestedClassToBuild, bool _nestedArray) + :fieldCreate(_parentBuilder->fieldCreate) + ,idSet(false) + ,parentBuilder(_parentBuilder) + ,nestedClassToBuild(_nestedClassToBuild) + ,nestedName(_nestedName) + ,nestedArray(_nestedArray) + ,createNested(true) {} void FieldBuilder::reset() @@ -737,7 +771,7 @@ void FieldBuilder::checkFieldName(const std::string& name) it != end; ++it) { if(name==*it) - throw std::invalid_argument("duplicate fieldName "+name); + THROW_EXCEPTION2(std::invalid_argument, std::string("duplicate fieldName ")+name); } } @@ -861,6 +895,18 @@ UnionConstPtr FieldBuilder::createUnion() FieldBuilderPtr FieldBuilder::addNestedStructure(string const & name) { + // linear search on the theory that the number of fields is small + for(size_t i=0; igetType()!=structure) + THROW_EXCEPTION2(std::invalid_argument, "nested field not structure: "+name); + + return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name, + static_cast(fields[i].get()))); + } return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name, structure, false)); } @@ -887,20 +933,39 @@ FieldBuilderPtr FieldBuilder::endNested() THROW_EXCEPTION2(std::runtime_error, "this method can only be called to create nested fields"); FieldConstPtr nestedField = createFieldInternal(nestedClassToBuild); - if (nestedArray) - parentBuilder->addArray(nestedName, nestedField); - else - parentBuilder->add(nestedName, nestedField); - - return parentBuilder; -} + if(createNested) { + if (nestedArray) + parentBuilder->addArray(nestedName, nestedField); + else + parentBuilder->add(nestedName, nestedField); + return parentBuilder; + } else { + for(size_t i=0, N = parentBuilder->fieldNames.size(); ifieldNames[i]) + continue; + assert(parentBuilder->fields[i]->getType()==structure); + + parentBuilder->fields[i] = nestedField; + return parentBuilder; + } + // this only reached if bug in ctor + THROW_EXCEPTION2(std::logic_error, "no nested field field?"); + } +} FieldBuilderPtr FieldCreate::createFieldBuilder() const { return FieldBuilderPtr(new FieldBuilder()); } +FieldBuilderPtr FieldCreate::createFieldBuilder(StructureConstPtr S) const +{ + FieldBuilderPtr ret(new FieldBuilder(S.get())); + return ret; +} + ScalarConstPtr FieldCreate::createScalar(ScalarType scalarType) const { if(scalarType<0 || scalarType>MAX_SCALAR_TYPE) { diff --git a/src/pv/pvIntrospect.h b/src/pv/pvIntrospect.h index 4dfb2a0..0f028fb 100644 --- a/src/pv/pvIntrospect.h +++ b/src/pv/pvIntrospect.h @@ -1021,6 +1021,8 @@ public: private: FieldBuilder(); + FieldBuilder(const Structure*); + FieldBuilder(const FieldBuilderPtr & _parentBuilder, const std::string& name, const Structure*); FieldBuilder(FieldBuilderPtr const & parentBuilder, std::string const & nestedName, Type nestedClassToBuild, bool nestedArray); @@ -1032,7 +1034,7 @@ private: friend class FieldCreate; - FieldCreatePtr fieldCreate; + const FieldCreatePtr fieldCreate; std::string id; bool idSet; @@ -1040,11 +1042,11 @@ private: StringArray fieldNames; FieldConstPtrArray fields; - FieldBuilderPtr parentBuilder; - Type nestedClassToBuild; - std::string nestedName; - bool nestedArray; - + const FieldBuilderPtr parentBuilder; + const Type nestedClassToBuild; + const std::string nestedName; + const bool nestedArray; + const bool createNested; // true - endNested() creates in parent, false - endNested() appends to parent }; /** @@ -1059,6 +1061,11 @@ public: * @return a new instance of a @c FieldBuilder. */ FieldBuilderPtr createFieldBuilder() const; + /** + * Create a new instance of in-line @c Field builder pre-initialized with and existing Structure + * @return a new instance of a @c FieldBuilder. + */ + FieldBuilderPtr createFieldBuilder(StructureConstPtr S) const; /** * Create a @c ScalarField. * @param scalarType The scalar type. diff --git a/testApp/pv/testFieldBuilder.cpp b/testApp/pv/testFieldBuilder.cpp index e32078c..94dda92 100644 --- a/testApp/pv/testFieldBuilder.cpp +++ b/testApp/pv/testFieldBuilder.cpp @@ -8,6 +8,7 @@ #include #include +#include using namespace epics::pvData; @@ -241,21 +242,73 @@ void test_nestedStructureArray() } +void test_extendStructure() +{ + testDiag("test_extendStructure()"); + Structure::const_shared_pointer X(getFieldCreate()->createFieldBuilder() + ->add("A", pvInt) + ->addNestedStructure("nest") + ->add("B", pvInt) + ->endNested() + ->createStructure()); + + Structure::const_shared_pointer Y(getFieldCreate()->createFieldBuilder(X) + ->add("A2", pvInt) + ->addNestedStructure("nest") + ->add("B2", pvInt) + ->endNested() + ->createStructure()); + + testOk1(X.get()!=Y.get()); + testOk1(X->getField("A")==Y->getField("A")); + testOk1(!X->getField("A2")); + testOk1(!!Y->getField("A2")); + testOk1(X->getField("nest")!=Y->getField("nest")); + testOk1(X->getField("nest")->getField("B")==Y->getField("nest")->getField("B")); + testOk1(!X->getField("nest")->getField("B2")); + testOk1(!!Y->getField("nest")->getField("B2")); + + try { + Structure::const_shared_pointer Z(getFieldCreate()->createFieldBuilder(Y) + ->add("A2", pvDouble) + ->createStructure()); + testFail("Unexpected success in adding duplicate field"); + }catch(std::exception& e){ + testPass("catch expected exception: %s", e.what()); + } + + try { + Structure::const_shared_pointer Z(getFieldCreate()->createFieldBuilder(Y) + ->addNestedStructure("nest") + ->add("B2", pvDouble) + ->endNested() + ->createStructure()); + testFail("Unexpected success in adding duplicate nested field"); + }catch(std::exception& e){ + testPass("catch expected exception: %s", e.what()); + } +} + } // namespace MAIN(testFieldBuilder) { - testPlan(68); - testDiag("Tests for FieldBuilder"); + testPlan(78); + try { + testDiag("Tests for FieldBuilder"); - test_factory(); - test_structure(); - test_arraySizeTypes(); - test_nestedStructure(); - test_nestedStructureArray(); - - - test_invalid(); + test_factory(); + test_structure(); + test_arraySizeTypes(); + test_nestedStructure(); + test_nestedStructureArray(); + test_extendStructure(); + + test_invalid(); + }catch(std::exception& e) { + PRINT_EXCEPTION(e); + testAbort("Unhandled exception: %s", e.what()); + } return testDone(); }