commit after merge

This commit is contained in:
Marty Kraimer
2013-11-06 07:42:03 -05:00
5 changed files with 1121 additions and 17 deletions

View File

@@ -11,6 +11,7 @@
#include <cstdlib>
#include <string>
#include <cstdio>
#include <stdexcept>
#include <pv/lock.h>
#include <pv/pvIntrospect.h>
#include <pv/convert.h>
@@ -68,7 +69,7 @@ struct StructureArrayHashFunction {
Scalar::Scalar(ScalarType scalarType)
: Field(scalar),scalarType(scalarType)
{
if(scalarType<pvBoolean || scalarType>pvString)
if(scalarType<0 || scalarType>MAX_SCALAR_TYPE)
throw std::invalid_argument("Can't construct Scalar from invalid ScalarType");
}
@@ -169,10 +170,49 @@ static StructureConstPtr deserializeStructureField(const FieldCreate* fieldCreat
return fieldCreate->createStructure(id, fieldNames, fields);
}
static void serializeUnionField(const Union* punion, ByteBuffer* buffer, SerializableControl* control)
{
// to optimize default (non-empty) IDs optimization
// empty IDs are not allowed
String id = punion->getID();
if (id == Union::DEFAULT_ID) // TODO slow comparison
SerializeHelper::serializeString(emptyString, buffer, control);
else
SerializeHelper::serializeString(id, buffer, control);
FieldConstPtrArray const & fields = punion->getFields();
StringArray const & fieldNames = punion->getFieldNames();
std::size_t len = fields.size();
SerializeHelper::writeSize(len, buffer, control);
for (std::size_t i = 0; i < len; i++)
{
SerializeHelper::serializeString(fieldNames[i], buffer, control);
control->cachedSerialize(fields[i], buffer);
}
}
static UnionConstPtr deserializeUnionField(const FieldCreate* fieldCreate, ByteBuffer* buffer, DeserializableControl* control)
{
String id = SerializeHelper::deserializeString(buffer, control);
const std::size_t size = SerializeHelper::readSize(buffer, control);
FieldConstPtrArray fields; fields.reserve(size);
StringArray fieldNames; fieldNames.reserve(size);
for (std::size_t i = 0; i < size; i++)
{
fieldNames.push_back(SerializeHelper::deserializeString(buffer, control));
fields.push_back(control->cachedDeserialize(buffer));
}
if (id.empty())
return fieldCreate->createUnion(fieldNames, fields);
else
return fieldCreate->createUnion(id, fieldNames, fields);
}
ScalarArray::ScalarArray(ScalarType elementType)
: Field(scalarArray),elementType(elementType)
{
if(elementType<pvBoolean || elementType>pvString)
if(elementType<0 || elementType>MAX_SCALAR_TYPE)
throw std::invalid_argument("Can't construct ScalarArray from invalid ScalarType");
}
@@ -264,6 +304,44 @@ void StructureArray::deserialize(ByteBuffer */*buffer*/, DeserializableControl *
throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
}
UnionArray::UnionArray(UnionConstPtr const & _punion)
: Field(unionArray),punion(_punion)
{
}
UnionArray::~UnionArray() {
if(debugLevel==highDebug) printf("~UnionArray\n");
}
String UnionArray::getID() const
{
return punion->getID() + "[]";
}
void UnionArray::toString(StringBuilder buffer,int indentLevel) const {
*buffer += getID();
newLine(buffer,indentLevel + 1);
punion->toString(buffer,indentLevel + 1);
}
void UnionArray::serialize(ByteBuffer *buffer, SerializableControl *control) const {
control->ensureBuffer(1);
if (punion->isVariant())
{
// unrestricted/variant union
buffer->putByte(0x92);
}
else
{
buffer->putByte(0x91);
control->cachedSerialize(punion, buffer);
}
}
void UnionArray::deserialize(ByteBuffer */*buffer*/, DeserializableControl */*control*/) {
throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
}
String Structure::DEFAULT_ID = "structure";
Structure::Structure (
@@ -356,6 +434,17 @@ void Structure::toStringCommon(StringBuilder buffer,int indentLevel) const{
newLine(buffer,indentLevel +1);
pfield->toString(buffer,indentLevel +1);
break;
case union_:
{
Field const *xxx = pfield.get();
Union const *pstruct = static_cast<Union const*>(xxx);
pstruct->toStringCommon(buffer,indentLevel + 1);
break;
}
case unionArray:
newLine(buffer,indentLevel +1);
pfield->toString(buffer,indentLevel +1);
break;
}
if(i<numberFields-1) newLine(buffer,indentLevel);
}
@@ -371,18 +460,315 @@ void Structure::deserialize(ByteBuffer */*buffer*/, DeserializableControl */*con
throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
}
String Union::DEFAULT_ID = "union";
String Union::ANY_ID = "any";
Union::Union ()
: Field(union_),
fieldNames(),
fields(),
id(ANY_ID)
{
}
Union::Union (
StringArray const & fieldNames,
FieldConstPtrArray const & infields,
String const & inid)
: Field(union_),
fieldNames(fieldNames),
fields(infields),
id(inid)
{
if(inid.empty()) {
throw std::invalid_argument("id is empty");
}
if(fieldNames.size()!=fields.size()) {
throw std::invalid_argument("fieldNames.size()!=fields.size()");
}
if(fields.size()==0 && inid!=ANY_ID) {
throw std::invalid_argument("no fields but id is different than " + ANY_ID);
}
size_t number = fields.size();
for(size_t i=0; i<number; i++) {
const String& name = fieldNames[i];
if(name.empty()) {
throw std::invalid_argument("fieldNames has a zero length string");
}
if(fields[i].get()==NULL)
throw std::invalid_argument("Can't construct Union with NULL Field");
// look for duplicates
for(size_t j=i+1; j<number; j++) {
String otherName = fieldNames[j];
int result = name.compare(otherName);
if(result==0) {
String message("duplicate fieldName ");
message += name;
throw std::invalid_argument(message);
}
}
}
}
Union::~Union() { }
String Union::getID() const
{
return id;
}
FieldConstPtr Union::getField(String const & fieldName) const {
size_t numberFields = fields.size();
for(size_t i=0; i<numberFields; i++) {
FieldConstPtr pfield = fields[i];
int result = fieldName.compare(fieldNames[i]);
if(result==0) return pfield;
}
return FieldConstPtr();
}
size_t Union::getFieldIndex(String const &fieldName) const {
size_t numberFields = fields.size();
for(size_t i=0; i<numberFields; i++) {
FieldConstPtr pfield = fields[i];
int result = fieldName.compare(fieldNames[i]);
if(result==0) return i;
}
return -1;
}
void Union::toString(StringBuilder buffer,int indentLevel) const{
*buffer += getID();
toStringCommon(buffer,indentLevel+1);
}
void Union::toStringCommon(StringBuilder buffer,int indentLevel) const{
newLine(buffer,indentLevel);
size_t numberFields = fields.size();
if (numberFields == 0) // variant support
return;
for(size_t i=0; i<numberFields; i++) {
FieldConstPtr pfield = fields[i];
*buffer += pfield->getID() + " " + fieldNames[i];
switch(pfield->getType()) {
case scalar:
case scalarArray:
break;
case structure:
{
Field const *xxx = pfield.get();
Structure const *pstruct = static_cast<Structure const*>(xxx);
pstruct->toStringCommon(buffer,indentLevel + 1);
break;
}
case structureArray:
newLine(buffer,indentLevel +1);
pfield->toString(buffer,indentLevel +1);
break;
case union_:
{
Field const *xxx = pfield.get();
Union const *pstruct = static_cast<Union const*>(xxx);
pstruct->toStringCommon(buffer,indentLevel + 1);
break;
}
case unionArray:
newLine(buffer,indentLevel +1);
pfield->toString(buffer,indentLevel +1);
break;
}
if(i<numberFields-1) newLine(buffer,indentLevel);
}
}
void Union::serialize(ByteBuffer *buffer, SerializableControl *control) const {
control->ensureBuffer(1);
if (fields.size() == 0)
{
// unrestricted/variant union
buffer->putByte(0x82);
}
else
{
buffer->putByte(0x81);
serializeUnionField(this, buffer, control);
}
}
void Union::deserialize(ByteBuffer */*buffer*/, DeserializableControl */*control*/) {
throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
}
FieldBuilder::FieldBuilder() : fieldCreate(getFieldCreate()), idSet(false) {}
FieldBuilder::FieldBuilder(FieldBuilderPtr const & _parentBuilder,
std::string const & _nestedName,
Type _nestedClassToBuild, bool _nestedArray) :
fieldCreate(getFieldCreate()),
idSet(false),
parentBuilder(_parentBuilder),
nestedClassToBuild(_nestedClassToBuild),
nestedName(_nestedName),
nestedArray(_nestedArray)
{}
void FieldBuilder::reset()
{
id.erase();
idSet = false;
fieldNames.clear();
fields.clear();
}
FieldBuilderPtr FieldBuilder::setId(std::string const & id)
{
this->id = id;
idSet = true;
return shared_from_this();
}
FieldBuilderPtr FieldBuilder::add(std::string const & name, ScalarType scalarType)
{
fields.push_back(fieldCreate->createScalar(scalarType)); fieldNames.push_back(name);
return shared_from_this();
}
FieldBuilderPtr FieldBuilder::add(std::string const & name, FieldConstPtr const & field)
{
fields.push_back(field); fieldNames.push_back(name);
return shared_from_this();
}
FieldBuilderPtr FieldBuilder::addArray(std::string const & name, ScalarType scalarType)
{
fields.push_back(fieldCreate->createScalarArray(scalarType)); fieldNames.push_back(name);
return shared_from_this();
}
FieldBuilderPtr FieldBuilder::addArray(std::string const & name, FieldConstPtr const & element)
{
switch (element->getType())
{
case structure:
fields.push_back(fieldCreate->createStructureArray(static_pointer_cast<const Structure>(element)));
break;
case union_:
fields.push_back(fieldCreate->createUnionArray(static_pointer_cast<const Union>(element)));
break;
case scalar:
fields.push_back(fieldCreate->createScalarArray(static_pointer_cast<const Scalar>(element)->getScalarType()));
break;
default:
throw std::invalid_argument("unsupported array element type:" + element->getType());
}
fieldNames.push_back(name);
return shared_from_this();
}
FieldConstPtr FieldBuilder::createFieldInternal(Type type)
{
// minor optimization
if (fieldNames.size() == 0 && type == union_)
return fieldCreate->createVariantUnion();
if (type == structure)
{
return (idSet) ?
fieldCreate->createStructure(id, fieldNames, fields) :
fieldCreate->createStructure(fieldNames, fields);
}
else if (type == union_)
{
return (idSet) ?
fieldCreate->createUnion(id, fieldNames, fields) :
fieldCreate->createUnion(fieldNames, fields);
}
else
throw std::invalid_argument("unsupported type: " + type);
}
StructureConstPtr FieldBuilder::createStructure()
{
if (parentBuilder.get())
throw std::runtime_error("createStructure() called in nested FieldBuilder");
StructureConstPtr field(static_pointer_cast<const Structure>(createFieldInternal(structure)));
reset();
return field;
}
UnionConstPtr FieldBuilder::createUnion()
{
if (parentBuilder.get())
throw std::runtime_error("createUnion() called in nested FieldBuilder");
UnionConstPtr field(static_pointer_cast<const Union>(createFieldInternal(union_)));
reset();
return field;
}
FieldBuilderPtr FieldBuilder::addStructure(std::string const & name)
{
return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name, structure, false));
}
FieldBuilderPtr FieldBuilder::addUnion(std::string const & name)
{
return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name, union_, false));
}
FieldBuilderPtr FieldBuilder::addStructureArray(std::string const & name)
{
return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name, structure, true));
}
FieldBuilderPtr FieldBuilder::addUnionArray(std::string const & name)
{
return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name, union_, true));
}
FieldBuilderPtr FieldBuilder::createNested()
{
if (!parentBuilder.get())
throw 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;
}
FieldBuilderPtr FieldCreate::createFieldBuilder() const
{
return FieldBuilderPtr(new FieldBuilder());
}
ScalarConstPtr FieldCreate::createScalar(ScalarType scalarType) const
{
// TODO use singleton instance
ScalarConstPtr scalar(new Scalar(scalarType), Field::Deleter());
return scalar;
if(scalarType<0 || scalarType>MAX_SCALAR_TYPE)
throw std::invalid_argument("Can't construct Scalar from invalid ScalarType");
return scalars[scalarType];
}
ScalarArrayConstPtr FieldCreate::createScalarArray(ScalarType elementType) const
{
// TODO use singleton instance
ScalarArrayConstPtr scalarArray(new ScalarArray(elementType), Field::Deleter());
return scalarArray;
if(elementType<0 || elementType>MAX_SCALAR_TYPE)
throw std::invalid_argument("Can't construct ScalarArray from invalid ScalarType");
return scalarArrays[elementType];
}
StructureConstPtr FieldCreate::createStructure (
@@ -411,6 +797,42 @@ StructureArrayConstPtr FieldCreate::createStructureArray(
return structureArray;
}
UnionConstPtr FieldCreate::createUnion (
StringArray const & fieldNames,FieldConstPtrArray const & fields) const
{
UnionConstPtr punion(
new Union(fieldNames,fields), Field::Deleter());
return punion;
}
UnionConstPtr FieldCreate::createUnion (
String const & id,
StringArray const & fieldNames,
FieldConstPtrArray const & fields) const
{
UnionConstPtr punion(
new Union(fieldNames,fields,id), Field::Deleter());
return punion;
}
UnionConstPtr FieldCreate::createVariantUnion () const
{
return variantUnion;
}
UnionArrayConstPtr FieldCreate::createUnionArray(
UnionConstPtr const & punion) const
{
UnionArrayConstPtr unionArray(
new UnionArray(punion), Field::Deleter());
return unionArray;
}
UnionArrayConstPtr FieldCreate::createVariantUnionArray () const
{
return variantUnionArray;
}
StructureConstPtr FieldCreate::appendField(
StructureConstPtr const & structure,
String const & fieldName,
@@ -522,13 +944,23 @@ FieldConstPtr FieldCreate::deserialize(ByteBuffer* buffer, DeserializableControl
int scalarType = decodeScalar(code);
if (scalarType == -1)
throw std::invalid_argument("invalid scalar type encoding");
return FieldConstPtr(new Scalar(static_cast<ScalarType>(scalarType)), Field::Deleter());
return scalars[scalarType];
}
else if (typeCode == 0x80)
{
// Type type = Type.structure;
return deserializeStructureField(this, buffer, control);
}
else if (typeCode == 0x81)
{
// Type type = Type.union;
return deserializeUnionField(this, buffer, control);
}
else if (typeCode == 0x82)
{
// Type type = Type.union; variant union (aka any type)
return variantUnion;
}
else
throw std::invalid_argument("invalid type encoding");
}
@@ -540,7 +972,7 @@ FieldConstPtr FieldCreate::deserialize(ByteBuffer* buffer, DeserializableControl
int scalarType = decodeScalar(code);
if (scalarType == -1)
throw std::invalid_argument("invalid scalarArray type encoding");
return FieldConstPtr(new ScalarArray(static_cast<ScalarType>(scalarType)), Field::Deleter());
return scalarArrays[scalarType];
}
else if (typeCode == 0x80)
{
@@ -548,6 +980,17 @@ FieldConstPtr FieldCreate::deserialize(ByteBuffer* buffer, DeserializableControl
StructureConstPtr elementStructure = std::tr1::static_pointer_cast<const Structure>(control->cachedDeserialize(buffer));
return FieldConstPtr(new StructureArray(elementStructure), Field::Deleter());
}
else if (typeCode == 0x81)
{
// Type type = Type.unionArray;
UnionConstPtr elementUnion = std::tr1::static_pointer_cast<const Union>(control->cachedDeserialize(buffer));
return FieldConstPtr(new UnionArray(elementUnion), Field::Deleter());
}
else if (typeCode == 0x82)
{
// Type type = Type.unionArray; variant union (aka any type)
return variantUnionArray;
}
else
throw std::invalid_argument("invalid type encoding");
}
@@ -564,7 +1007,16 @@ FieldCreatePtr FieldCreate::getFieldCreate()
return fieldCreate;
}
FieldCreate::FieldCreate(){}
FieldCreate::FieldCreate()
{
for (int i = 0; i <= MAX_SCALAR_TYPE; i++)
{
scalars.push_back(ScalarConstPtr(new Scalar(static_cast<ScalarType>(i)), Field::Deleter()));
scalarArrays.push_back(ScalarArrayConstPtr(new ScalarArray(static_cast<ScalarType>(i)), Field::Deleter()));
}
variantUnion = UnionConstPtr(new Union(), Field::Deleter());
variantUnionArray = UnionArrayConstPtr(new UnionArray(variantUnion), Field::Deleter());
}
FieldCreatePtr getFieldCreate() {
return FieldCreate::getFieldCreate();

View File

@@ -24,6 +24,8 @@ class Scalar;
class ScalarArray;
class Structure;
class StructureArray;
class Union;
class UnionArray;
/**
* typedef for a shared pointer to an immutable Field.
@@ -49,6 +51,14 @@ typedef std::tr1::shared_ptr<const Structure> StructureConstPtr;
* typedef for a shared pointer to an immutable StructureArray.
*/
typedef std::tr1::shared_ptr<const StructureArray> StructureArrayConstPtr;
/**
* typedef for a shared pointer to an immutable Union.
*/
typedef std::tr1::shared_ptr<const Union> UnionConstPtr;
/**
* typedef for a shared pointer to an immutable UnionArray.
*/
typedef std::tr1::shared_ptr<const UnionArray> UnionArrayConstPtr;
/**
* Definition of support field types.
@@ -69,7 +79,15 @@ enum Type {
/**
* The type is structureArray. Each element is a structure.
*/
structureArray
structureArray,
/**
* The type is an union.
*/
union_,
/**
* The type is an array of unions.
*/
unionArray
};
/**
@@ -144,6 +162,8 @@ enum ScalarType {
pvString
};
#define MAX_SCALAR_TYPE pvString
/**
* Convenience functions for ScalarType.
*/
@@ -381,6 +401,48 @@ private:
friend class FieldCreate;
};
/**
* This class implements introspection object for a unionArray
*/
class UnionArray : public Field{
public:
POINTER_DEFINITIONS(UnionArray);
typedef UnionArray& reference;
typedef const UnionArray& const_reference;
/**
* Get the introspection interface for the array elements.
* @return The introspection interface.
*/
UnionConstPtr getUnion() const {return punion;}
/**
* Convert the scalarType to a string and add it to builder.
* @param builder The string builder.
* @param indentLevel The number of blanks at the beginning of new lines.
*/
virtual void toString(StringBuilder buf,int indentLevel=0) const;
virtual String getID() const;
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
protected:
/**
* Constructor.
* @param union The introspection interface for the elements.
*/
UnionArray(UnionConstPtr const & _punion);
/**
* Destructor.
*/
virtual ~UnionArray();
private:
UnionConstPtr punion;
friend class FieldCreate;
};
/**
* This class implements introspection object for a structure.
*/
@@ -401,7 +463,7 @@ public:
typedef const Structure& const_reference;
/**
* Get the number of immediate subfields in the structure/
* Get the number of immediate subfields in the structure.
* @return The number of fields.
*/
std::size_t getNumberFields() const {return fieldNames.size();}
@@ -468,6 +530,108 @@ private:
FieldConstPtrArray fields;
String id;
friend class FieldCreate;
friend class Union;
};
/**
* This class implements introspection object for a union.
*/
class Union : public Field {
public:
POINTER_DEFINITIONS(Union);
/**
* Default union ID.
*/
static epics::pvData::String DEFAULT_ID;
/**
* Default variant union ID.
*/
static epics::pvData::String ANY_ID;
/**
* Destructor.
*/
virtual ~Union();
typedef Union& reference;
typedef const Union& const_reference;
/**
* Get the number of immediate subfields in the union.
* @return The number of fields.
*/
std::size_t getNumberFields() const {return fieldNames.size();}
/**
* Get the field for the specified fieldName.
* @param fieldName The name of the field to get;
* @return The introspection interface.
* This will hold a null pointer if the field is not in the union.
*/
FieldConstPtr getField(String const &fieldName) const;
/**
* Get the field for the specified fieldName.
* @param fieldName The index of the field to get;
* @return The introspection interface.
* This will hold a null pointer if the field is not in the union.
*/
FieldConstPtr getField(std::size_t index) const {return fields[index];}
/**
* Get the field index for the specified fieldName.
* @return The introspection interface.
* This will be -1 if the field is not in the union.
*/
std::size_t getFieldIndex(String const &fieldName) const;
/**
* Get the fields in the union.
* @return The array of fields.
*/
FieldConstPtrArray const & getFields() const {return fields;}
/**
* Get the names of the fields in the union.
* @return The array of fieldNames.
*/
StringArray const & getFieldNames() const {return fieldNames;}
void renameField(std::size_t fieldIndex,String const & newName)
{fieldNames[fieldIndex] = newName;}
/**
* Get the name of the field with the specified index;
* @param fieldIndex The index of the desired field.
* @return The fieldName.
*/
String getFieldName(std::size_t fieldIndex) const {return fieldNames[fieldIndex];}
/**
* Check if this union is variant union (aka any type).
* @return <code>true</code> if this union is variant union, otherwise <code>false</code>.
*/
bool isVariant() const {return (fieldNames.size() == 0);}
/**
* Convert the union to a string and add it to builder.
* @param builder The string builder.
*/
virtual void toString(StringBuilder buf) const{toString(buf,0);}
/**
* Convert the union to a string and add it to builder.
* @param builder The string builder.
* @param indentLevel The number of blanks at the beginning of new lines.
*/
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual String getID() const;
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
protected:
Union();
Union(StringArray const & fieldNames, FieldConstPtrArray const & fields, String const & id = DEFAULT_ID);
private:
void toStringCommon(StringBuilder buf,int indentLevel) const;
StringArray fieldNames;
FieldConstPtrArray fields;
String id;
friend class FieldCreate;
friend class Structure;
};
/**
@@ -476,16 +640,162 @@ private:
class FieldCreate;
typedef std::tr1::shared_ptr<FieldCreate> FieldCreatePtr;
class FieldBuilder;
typedef std::tr1::shared_ptr<FieldBuilder> FieldBuilderPtr;
/**
* Interface for in-line creating of introspection interfaces.
* One instance can be used to create multiple {@code Field} instances.
* An instance of this object must not be used concurrently (an object has a state).
* @author mse
*/
class FieldBuilder :
public std::tr1::enable_shared_from_this<FieldBuilder>
{
public:
/**
* Set ID of an object to be created.
* @param id id to be set.
* @return this instance of a {@code FieldBuilder}.
*/
FieldBuilderPtr setId(std::string const & id);
/**
* Add a {@code Scalar}.
* @param name name of the array.
* @param scalarType type of a scalar to add.
* @return this instance of a {@code FieldBuilder}.
*/
FieldBuilderPtr add(std::string const & name, ScalarType scalarType);
/**
* Add a {@code Field} (e.g. {@code Structure}, {@code Union}).
* @param name name of the array.
* @param field a field to add.
* @return this instance of a {@code FieldBuilder}.
*/
FieldBuilderPtr add(std::string const & name, FieldConstPtr const & field);
/**
* Add array of {@code Scalar} elements.
* @param name name of the array.
* @param scalarType type of a scalar element.
* @return this instance of a {@code FieldBuilder}.
*/
FieldBuilderPtr addArray(std::string const & name, ScalarType scalarType);
/**
* Add array of {@code Field} elements.
* @param name name of the array.
* @param field a type of an array element.
* @return this instance of a {@code FieldBuilder}.
*/
FieldBuilderPtr addArray(std::string const & name, FieldConstPtr const & element);
/**
* Create a {@code Structure}.
* This resets this instance state and allows new {@code Field} instance to be created.
* @return a new instance of a {@code Structure}.
*/
StructureConstPtr createStructure();
/**
* Create an {@code Union}.
* This resets this instance state and allows new {@code Field} instance to be created.
* @return a new instance of an {@code Union}.
*/
UnionConstPtr createUnion();
/**
* Add new nested {@code Structure}.
* {@code createNested()} method must be called
* to complete creation of the nested {@code Structure}.
* @param name nested structure name.
* @return a new instance of a {@code FieldBuilder} is returned.
* @see #createNested()
*/
FieldBuilderPtr addStructure(std::string const & name);
/**
* Add new nested {@code Union}.
* {@code createNested()} method must be called
* to complete creation of the nested {@code Union}.
* @param name nested union name.
* @return a new instance of a {@code FieldBuilder} is returned.
* @see #createNested()
*/
FieldBuilderPtr addUnion(std::string const & name);
/**
* Add new nested {@code Structure[]}.
* {@code createNested()} method must be called
* to complete creation of the nested {@code Structure}.
* @param name nested structure name.
* @return a new instance of a {@code FieldBuilder} is returned.
* @see #createNested()
*/
FieldBuilderPtr addStructureArray(std::string const & name);
/**
* Add new nested {@code Union[]}.
* {@code createNested()} method must be called
* to complete creation of the nested {@code Union}.
* @param name nested union name.
* @return a new instance of a {@code FieldBuilder} is returned.
* @see #createNested()
*/
FieldBuilderPtr addUnionArray(std::string const & name);
/**
* Complete the creation of a nested object.
* @see #addStructure(String)
* @see #addUnion(String)
* @return a previous (parent) {@code FieldBuilder}.
*/
FieldBuilderPtr createNested();
private:
FieldBuilder();
FieldBuilder(FieldBuilderPtr const & parentBuilder,
std::string const & nestedName,
Type nestedClassToBuild, bool nestedArray);
void reset();
FieldConstPtr createFieldInternal(Type type);
friend class FieldCreate;
FieldCreatePtr fieldCreate;
std::string id;
bool idSet;
// NOTE: this preserves order, however it does not handle duplicates
StringArray fieldNames;
FieldConstPtrArray fields;
FieldBuilderPtr parentBuilder;
Type nestedClassToBuild;
std::string nestedName;
bool nestedArray;
};
class FieldCreate {
public:
static FieldCreatePtr getFieldCreate();
static FieldCreatePtr getFieldCreate();
/**
* Create a new instance of in-line {@code Field} builder.
* @return a new instance of a {@code FieldBuilder}.
*/
FieldBuilderPtr createFieldBuilder() const;
/**
* Create a {@code ScalarField}.
* @param scalarType The scalar type.
* @return a {@code Scalar} interface for the newly created object.
* @throws An {@code IllegalArgumentException} if an illegal type is specified.
*/
ScalarConstPtr createScalar(ScalarType scalarType) const;
ScalarConstPtr createScalar(ScalarType scalarType) const;
/**
* Create an {@code Array} field.
* @param elementType The {@code scalarType} for array elements
@@ -519,6 +829,43 @@ public:
String const & id,
StringArray const & fieldNames,
FieldConstPtrArray const & fields) const;
/**
* Create an {@code Array} field that is has element type <i>Union</i>
* @param fieldName The field name
* @param elementUnion The {@code Union} for each array element.
* @return An {@code Array} Interface for the newly created object.
*/
UnionArrayConstPtr createUnionArray(UnionConstPtr const & punion) const;
/**
* Create a variant {@code UnionArray} (aka any type) field.
* @return a {@code UnionArray} interface for the newly created object.
*/
UnionArrayConstPtr createVariantUnionArray() const;
/**
* Create a variant {@code Union} (aka any type) field.
* @return a {@code Union} interface for the newly created object.
*/
UnionConstPtr createVariantUnion() const;
/**
* Create a {@code Union} field.
* @param fieldNames The array of {@code fieldNames} for the union.
* @param fields The array of {@code fields} for the union.
* @return a {@code Union} interface for the newly created object.
*/
UnionConstPtr createUnion (
StringArray const & fieldNames,
FieldConstPtrArray const & fields) const;
/**
* Create a {@code Union} field with identification string.
* @param id The identification string for the union.
* @param fieldNames The array of {@code fieldNames} for the union.
* @param fields The array of {@code fields} for the union.
* @return a {@code Union} interface for the newly created object.
*/
UnionConstPtr createUnion (
String const & id,
StringArray const & fieldNames,
FieldConstPtrArray const & fields) const;
/**
* Append a field to a structure.
* @param structure The structure to which the field is appended.
@@ -549,7 +896,12 @@ public:
FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
private:
FieldCreate();
FieldCreate();
std::vector<ScalarConstPtr> scalars;
std::vector<ScalarArrayConstPtr> scalarArrays;
UnionConstPtr variantUnion;
UnionArrayConstPtr variantUnionArray;
};
/**

View File

@@ -53,6 +53,10 @@ PROD_HOST += testOperators
testOperators_SRCS += testOperators.cpp
testOperators_LIBS += pvData Com
PROD_HOST += testFieldBuilder
testFieldBuilder_SRCS += testFieldBuilder.cpp
testFieldBuilder_LIBS += pvData Com
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES

View File

@@ -0,0 +1,239 @@
#include <string>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <pv/pvData.h>
using namespace epics::pvData;
using namespace std;
using namespace std::tr1;
void test_factory()
{
testDiag("Test test_factory()");
FieldCreatePtr fieldCreate = getFieldCreate();
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
testOk1(fb.get() != 0);
FieldBuilderPtr fb2 = fieldCreate->createFieldBuilder();
testOk1(fb.get() != fb2.get());
}
void test_structure()
{
testDiag("Test test_structure()");
FieldCreatePtr fieldCreate = getFieldCreate();
FieldBuilderPtr fb = fieldCreate->createFieldBuilder();
// test with simple (non-nested) structure
std::string ID = "testStructureID";
StructureConstPtr s = fb->setId(ID)->
add("double", pvDouble)->
addArray("intArray", pvInt)->
createStructure();
testOk1(s.get() != 0);
testOk1(ID == s->getID());
testOk1(2 == s->getFields().size());
FieldConstPtr f0 = s->getField(0);
testOk1(scalar == f0->getType());
testOk1("double" == s->getFieldName(0));
testOk(pvDouble == static_pointer_cast<const Scalar>(f0)->getScalarType(), "f0 scalar type == double");
FieldConstPtr f1 = s->getField(1);
testOk1(scalarArray == f1->getType());
testOk1("intArray" == s->getFieldName(1));
testOk(pvInt == static_pointer_cast<const ScalarArray>(f1)->getElementType(), "f1 element type == int");
// test reuse with empty structure
StructureConstPtr emptyStructure = fb->createStructure();
testOk1(emptyStructure.get() != 0);
testOk1(Structure::DEFAULT_ID == emptyStructure->getID());
testOk1(0 == emptyStructure->getFields().size());
// test add/addArray with Field
StructureConstPtr s2 = fb->add("s", s)->
addArray("sArray", s)->
createStructure();
testOk1(s2 != 0);
testOk1(Structure::DEFAULT_ID == s2->getID());
testOk1(2 == s2->getFields().size());
f0 = s2->getField(0);
testOk1(structure == f0->getType());
testOk1("s" == s2->getFieldName(0));
testOk1(s.get() == f0.get());
f1 = s2->getField(1);
testOk1(structureArray == f1->getType());
testOk1("sArray" == s2->getFieldName(1));
testOk(s.get() == static_pointer_cast<const StructureArray>(f1)->getStructure().get(), "array element is given structure");
}
void test_invalid()
{
testDiag("Test test_invalid()");
FieldCreatePtr fieldCreate = getFieldCreate();
try
{
fieldCreate->createFieldBuilder()->
add("f1", pvByte)->
createNested();
testFail("createNested() allowed in non-nested FieldBuilder");
}
catch (std::runtime_error& re) {
// ok
testPass("createNested() disallowed in non-nested FieldBuilder");
}
try
{
fieldCreate->createFieldBuilder()->
add("f1", pvByte)->
addStructure("nested")->
add("n1", pvUInt)->
createStructure();
testFail("createStructure() allowed in nested FieldBuilder");
}
catch (std::runtime_error& re) {
// ok
testPass("createStructure() disallowed in nested FieldBuilder");
}
}
void test_nestedStructure()
{
testDiag("Test test_nestedStructure()");
FieldCreatePtr fieldCreate = getFieldCreate();
std::string NESTED_ID = "nestedID";
StructureConstPtr s = fieldCreate->createFieldBuilder()->
add("double", pvDouble)->
addStructure("nested")->
setId(NESTED_ID)->
add("short", pvShort)->
add("long", pvLong)->
createNested()->
addArray("intArray", pvInt)->
createStructure();
testOk1(s.get() != 0);
testOk1(Structure::DEFAULT_ID == s->getID());
testOk1(3 == s->getFields().size());
FieldConstPtr f0 = s->getField(0);
testOk1(scalar == f0->getType());
testOk1("double" == s->getFieldName(0));
testOk(pvDouble == static_pointer_cast<const Scalar>(f0)->getScalarType(), "f0 scalar type == double");
FieldConstPtr f1 = s->getField(1);
testOk1(structure == f1->getType());
testOk1("nested" == s->getFieldName(1));
{
StructureConstPtr s2 = static_pointer_cast<const Structure>(f1);
testOk1(s2.get() != 0);
testOk1(NESTED_ID == s2->getID());
testOk1(2 == s2->getFields().size());
FieldConstPtr f20 = s2->getField(0);
testOk1(scalar == f20->getType());
testOk1("short" == s2->getFieldName(0));
testOk(pvShort == static_pointer_cast<const Scalar>(f20)->getScalarType(), "f20 scalar type == short");
FieldConstPtr f21 = s2->getField(1);
testOk1(scalar == f21->getType());
testOk1("long" == s2->getFieldName(1));
testOk(pvLong == static_pointer_cast<const Scalar>(f21)->getScalarType(), "f21 element type == long");
}
FieldConstPtr f2 = s->getField(2);
testOk1(scalarArray == f2->getType());
testOk1("intArray" == s->getFieldName(2));
testOk(pvInt == static_pointer_cast<const ScalarArray>(f2)->getElementType(), "f2 element type == int");
}
void test_nestedStructureArray()
{
testDiag("Test test_nestedStructureArray()");
FieldCreatePtr fieldCreate = getFieldCreate();
std::string NESTED_ID = "nestedID";
StructureConstPtr s = fieldCreate->createFieldBuilder()->
add("double", pvDouble)->
addStructureArray("nested")->
setId(NESTED_ID)->
add("short", pvShort)->
add("long", pvLong)->
createNested()->
addArray("intArray", pvInt)->
createStructure();
testOk1(s.get() != 0);
testOk1(Structure::DEFAULT_ID == s->getID());
testOk1(3 == s->getFields().size());
FieldConstPtr f0 = s->getField(0);
testOk1(scalar == f0->getType());
testOk1("double" == s->getFieldName(0));
testOk(pvDouble == static_pointer_cast<const Scalar>(f0)->getScalarType(), "f0 scalar type == double");
FieldConstPtr f1 = s->getField(1);
testOk1(structureArray == f1->getType());
testOk1("nested" == s->getFieldName(1));
{
StructureConstPtr s2 = static_pointer_cast<const StructureArray>(f1)->getStructure();
testOk1(s2.get() != 0);
testOk1(NESTED_ID == s2->getID());
testOk1(2 == s2->getFields().size());
FieldConstPtr f20 = s2->getField(0);
testOk1(scalar == f20->getType());
testOk1("short" == s2->getFieldName(0));
testOk(pvShort == static_pointer_cast<const Scalar>(f20)->getScalarType(), "f20 scalar type == short");
FieldConstPtr f21 = s2->getField(1);
testOk1(scalar == f21->getType());
testOk1("long" == s2->getFieldName(1));
testOk(pvLong == static_pointer_cast<const Scalar>(f21)->getScalarType(), "f21 element type == long");
}
FieldConstPtr f2 = s->getField(2);
testOk1(scalarArray == f2->getType());
testOk1("intArray" == s->getFieldName(2));
testOk(pvInt == static_pointer_cast<const ScalarArray>(f2)->getElementType(), "f2 element type == int");
}
MAIN(testFieldBuilder)
{
testPlan(65);
testDiag("Tests for FieldBuilder");
test_factory();
test_structure();
test_nestedStructure();
test_nestedStructureArray();
test_invalid();
return testDone();
}

View File

@@ -128,6 +128,62 @@ static void testStructure()
testOk1(struct1arr->getID()=="structure[]");
}
static void testUnion()
{
testDiag("testUnion");
StringArray names1(2);
names1[0] = "innerA";
names1[1] = "innerB";
FieldConstPtrArray fields1(2);
fields1[0] = fieldCreate->createScalar(pvDouble);
fields1[1] = fieldCreate->createScalarArray(pvString);
UnionConstPtr union1 = fieldCreate->createUnion(names1, fields1);
testOk1(union1->getNumberFields()==2);
testOk1(union1->getField("innerA")==fields1[0]);
testOk1(union1->getField("innerB")==fields1[1]);
testOk1(union1->getFieldIndex("innerA")==0);
testOk1(union1->getFieldIndex("innerB")==1);
testOk1(union1->getField(0)==fields1[0]);
testOk1(union1->getField(1)==fields1[1]);
testOk1(union1->getFieldName(0)==names1[0]);
testOk1(union1->getFieldName(1)==names1[1]);
testOk1(union1->getID() == Union::DEFAULT_ID);
testOk1(fields1 == union1->getFields()); // vector equality
StringArray names2(2);
names2[0] = "outerA";
names2[1] = "outerB";
FieldConstPtrArray fields2(2);
fields2[0] = fieldCreate->createScalar(pvInt);
fields2[1] = std::tr1::static_pointer_cast<const Field>(union1);
UnionConstPtr union2 = fieldCreate->createUnion(names2, fields2);
testOk1(union2->getNumberFields()==2); // not recursive
testOk1(union2->getField(1)==fields2[1]);
UnionArrayConstPtr union1arr = fieldCreate->createUnionArray(union1);
testOk1(union1arr->getUnion()==union1);
testOk1(union1arr->getID()=="union[]");
UnionConstPtr variantUnion1 = fieldCreate->createVariantUnion();
testOk1(variantUnion1->getNumberFields()==0);
testOk1(variantUnion1->getID() == Union::ANY_ID);
UnionArrayConstPtr variantUnion1arr = fieldCreate->createVariantUnionArray();
testOk1(variantUnion1arr->getUnion()==variantUnion1);
testOk1(variantUnion1arr->getID()=="any[]");
}
#define testExcept(EXCEPT, CMD) try{ CMD; testFail( "No exception from: " #CMD); } \
catch(EXCEPT& e) {testPass("Got expected exception from: " #CMD);} \
catch(std::exception& e) {testFail("Got wrong exception %s(%s) from: " #CMD, typeid(e).name(),e.what());} \
@@ -198,13 +254,14 @@ static void testMapping()
MAIN(testIntrospect)
{
testPlan(161);
testPlan(180);
fieldCreate = getFieldCreate();
pvDataCreate = getPVDataCreate();
standardField = getStandardField();
testScalar();
testScalarArray();
testStructure();
testUnion();
testError();
testMapping();
return testDone();