Union/UnionArray implemented, PVUnion/PVUnionArray not yet implemented; also implemented reuse of scalar/scalarArray instances in FieldCreate

This commit is contained in:
Matej Sekoranja
2013-11-05 16:15:12 +01:00
parent c56c976a22
commit cbf7b69ef0
3 changed files with 590 additions and 38 deletions

View File

@@ -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();