Union/UnionArray implemented, PVUnion/PVUnionArray not yet implemented; also implemented reuse of scalar/scalarArray instances in FieldCreate
This commit is contained in:
@@ -69,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");
|
||||
}
|
||||
|
||||
@@ -170,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");
|
||||
}
|
||||
|
||||
@@ -265,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 (
|
||||
@@ -357,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);
|
||||
}
|
||||
@@ -372,6 +460,149 @@ 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,
|
||||
@@ -425,9 +656,9 @@ FieldBuilderPtr FieldBuilder::addArray(std::string const & name, FieldConstPtr c
|
||||
case structure:
|
||||
fields.push_back(fieldCreate->createStructureArray(static_pointer_cast<const Structure>(element)));
|
||||
break;
|
||||
// TODO case union:
|
||||
// fields.push_back(fieldCreate->createUnionArray(static_pointer_cast<const Union>(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;
|
||||
@@ -441,25 +672,22 @@ FieldBuilderPtr FieldBuilder::addArray(std::string const & name, FieldConstPtr c
|
||||
|
||||
FieldConstPtr FieldBuilder::createFieldInternal(Type type)
|
||||
{
|
||||
/* TODO
|
||||
// minor optimization
|
||||
if (fieldNames.size() == 0 && type == union)
|
||||
if (fieldNames.size() == 0 && type == union_)
|
||||
return fieldCreate->createVariantUnion();
|
||||
*/
|
||||
|
||||
if (type == structure)
|
||||
{
|
||||
return (idSet) ?
|
||||
fieldCreate->createStructure(id, fieldNames, fields) :
|
||||
fieldCreate->createStructure(fieldNames, fields);
|
||||
}
|
||||
/* TODO
|
||||
else if (type == union)
|
||||
else if (type == union_)
|
||||
{
|
||||
return (idSet) ?
|
||||
fieldCreate->createUnion(id, fieldNames, fields) :
|
||||
fieldCreate->createUnion(fieldNames, fields);
|
||||
}
|
||||
*/
|
||||
else
|
||||
throw std::invalid_argument("unsupported type: " + type);
|
||||
}
|
||||
@@ -475,42 +703,37 @@ StructureConstPtr FieldBuilder::createStructure()
|
||||
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)));
|
||||
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));
|
||||
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));
|
||||
return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name, union_, true));
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
FieldBuilderPtr FieldBuilder::createNested()
|
||||
{
|
||||
@@ -529,22 +752,23 @@ FieldBuilderPtr FieldBuilder::createNested()
|
||||
|
||||
FieldBuilderPtr FieldCreate::createFieldBuilder() const
|
||||
{
|
||||
FieldBuilderPtr builder(new FieldBuilder());
|
||||
return builder;
|
||||
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 (
|
||||
@@ -573,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,
|
||||
@@ -684,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");
|
||||
}
|
||||
@@ -702,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)
|
||||
{
|
||||
@@ -710,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");
|
||||
}
|
||||
@@ -726,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();
|
||||
|
||||
Reference in New Issue
Block a user