PVUnion/PVUnionArray support and tests

This commit is contained in:
Matej Sekoranja
2013-11-07 14:12:26 +01:00
parent cbf7b69ef0
commit d40c41048d
15 changed files with 1416 additions and 41 deletions

View File

@@ -66,6 +66,8 @@ LIBSRCS += PVArray.cpp
LIBSRCS += PVScalarArray.cpp
LIBSRCS += PVStructure.cpp
LIBSRCS += PVStructureArray.cpp
LIBSRCS += PVUnion.cpp
LIBSRCS += PVUnionArray.cpp
LIBSRCS += PVDataCreateFactory.cpp
LIBSRCS += Convert.cpp
LIBSRCS += pvSubArrayCopy.cpp

View File

@@ -48,6 +48,16 @@ bool operator==(const Field& a, const Field& b)
const StructureArray &B=static_cast<const StructureArray&>(b);
return A==B;
}
case union_: {
const Union &A=static_cast<const Union&>(a);
const Union &B=static_cast<const Union&>(b);
return A==B;
}
case unionArray: {
const UnionArray &A=static_cast<const UnionArray&>(a);
const UnionArray &B=static_cast<const UnionArray&>(b);
return A==B;
}
default:
throw std::logic_error("Invalid Field type in comparision");
}
@@ -94,6 +104,33 @@ bool operator==(const StructureArray& a, const StructureArray& b)
return *(a.getStructure().get())==*(b.getStructure().get());
}
bool operator==(const Union& a, const Union& b)
{
if(&a==&b)
return true;
if (a.getID()!=b.getID())
return false;
size_t nflds=a.getNumberFields();
if (b.getNumberFields()!=nflds)
return false;
// std::equals does not work, since FieldConstPtrArray is an array of shared_pointers
FieldConstPtrArray af = a.getFields();
FieldConstPtrArray bf = b.getFields();
for (size_t i = 0; i < nflds; i++)
if (*(af[i].get()) != *(bf[i].get()))
return false;
StringArray an = a.getFieldNames();
StringArray bn = b.getFieldNames();
return std::equal( an.begin(), an.end(), bn.begin() );
}
bool operator==(const UnionArray& a, const UnionArray& b)
{
return *(a.getUnion().get())==*(b.getUnion().get());
}
// PVXXX object comparison
namespace {
@@ -210,6 +247,59 @@ bool compareField(const PVStructureArray* left, const PVStructureArray* right)
return true;
}
bool compareField(const PVUnion* left, const PVUnion* right)
{
UnionConstPtr ls = left->getUnion();
if(*ls!=*right->getUnion())
return false;
if (ls->isVariant())
{
PVFieldPtr lval = left->get();
if (lval.get() == 0)
return right->get().get() == 0;
else
return *(lval.get()) == *(right->get().get());
}
else
{
int32 lix = left->getSelectedIndex();
if (lix == right->getSelectedIndex())
{
if (lix == PVUnion::UNDEFINED_INDEX || *(left->get()) == *(right->get().get()))
return true;
else
return false;
}
else
return false;
}
}
bool compareField(const PVUnionArray* left, const PVUnionArray* right)
{
if(*left->getUnionArray()->getUnion()
!= *right->getUnionArray()->getUnion())
return false;
PVUnionArray::const_svector ld=left->view(), rd=right->view();
if(ld.size()!=rd.size())
return false;
PVUnionArray::const_svector::const_iterator lit, lend, rit;
for(lit=ld.begin(), lend=ld.end(), rit=rd.begin();
lit!=lend;
++lit, ++rit)
{
if(**lit != **rit)
return false;
}
return true;
}
} // end namespace
// untyped comparison
@@ -228,6 +318,8 @@ bool operator==(const PVField& left, const PVField& right)
case scalarArray: return compareField(static_cast<const PVScalarArray*>(&left), static_cast<const PVScalarArray*>(&right));
case structure: return compareField(static_cast<const PVStructure*>(&left), static_cast<const PVStructure*>(&right));
case structureArray: return compareField(static_cast<const PVStructureArray*>(&left), static_cast<const PVStructureArray*>(&right));
case union_: return compareField(static_cast<const PVUnion*>(&left), static_cast<const PVUnion*>(&right));
case unionArray: return compareField(static_cast<const PVUnionArray*>(&left), static_cast<const PVUnionArray*>(&right));
}
throw std::logic_error("PVField with invalid type!");
}

View File

@@ -84,7 +84,7 @@ size_t Convert::fromString(PVStructurePtr const &pvStructure, StringArray const
processed++;
}
else {
// structureArray not supported
// union, structureArray, unionArray not supported
String message("Convert::fromString unsupported fieldType ");
TypeFunc::toString(&message,type);
throw std::logic_error(message);
@@ -176,6 +176,18 @@ bool Convert::isCopyCompatible(FieldConstPtr const &from, FieldConstPtr const &t
StructureArrayConstPtr yyy = static_pointer_cast<const StructureArray>(to);
return isCopyStructureArrayCompatible(xxx,yyy);
}
case union_:
{
UnionConstPtr xxx = static_pointer_cast<const Union>(from);
UnionConstPtr yyy = static_pointer_cast<const Union>(to);
return isCopyUnionCompatible(xxx,yyy);
}
case unionArray:
{
UnionArrayConstPtr xxx = static_pointer_cast<const UnionArray>(from);
UnionArrayConstPtr yyy = static_pointer_cast<const UnionArray>(to);
return isCopyUnionArrayCompatible(xxx,yyy);
}
}
String message("Convert::isCopyCompatible should never get here");
throw std::logic_error(message);
@@ -211,6 +223,19 @@ void Convert::copy(PVFieldPtr const & from, PVFieldPtr const & to)
copyStructureArray(fromArray,toArray);
return;
}
case union_:
{
PVUnionPtr xxx = static_pointer_cast<PVUnion>(from);
PVUnionPtr yyy = static_pointer_cast<PVUnion>(to);
copyUnion(xxx,yyy);
return;
}
case unionArray: {
PVUnionArrayPtr fromArray = static_pointer_cast<PVUnionArray>(from);
PVUnionArrayPtr toArray = static_pointer_cast<PVUnionArray>(to);
copyUnionArray(fromArray,toArray);
return;
}
}
}
@@ -291,6 +316,19 @@ bool Convert::isCopyStructureCompatible(
StructureArrayConstPtr yyy = static_pointer_cast<const StructureArray>(to);
if(!isCopyStructureArrayCompatible(xxx,yyy)) return false;
}
case union_:
{
UnionConstPtr xxx = static_pointer_cast<const Union>(from);
UnionConstPtr yyy = static_pointer_cast<const Union>(to);
if(!isCopyUnionCompatible(xxx,yyy)) return false;
}
break;
case unionArray:
{
UnionArrayConstPtr xxx = static_pointer_cast<const UnionArray>(from);
UnionArrayConstPtr yyy = static_pointer_cast<const UnionArray>(to);
if(!isCopyUnionArrayCompatible(xxx,yyy)) return false;
}
break;
}
}
@@ -380,10 +418,60 @@ void Convert::copyStructure(PVStructurePtr const & from, PVStructurePtr const &
copyStructureArray(fromArray,toArray);
break;
}
case union_:
{
PVUnionPtr xxx = static_pointer_cast<PVUnion>(fromData);
PVUnionPtr yyy = static_pointer_cast<PVUnion>(toData);
copyUnion(xxx,yyy);
break;
}
case unionArray:
{
PVUnionArrayPtr fromArray =
static_pointer_cast<PVUnionArray>(fromData);
PVUnionArrayPtr toArray =
static_pointer_cast<PVUnionArray>(toData);
copyUnionArray(fromArray,toArray);
break;
}
}
}
}
bool Convert::isCopyUnionCompatible(
UnionConstPtr const &from, UnionConstPtr const &to)
{
return *(from.get()) == *(to.get());
}
void Convert::copyUnion(PVUnionPtr const & from, PVUnionPtr const & to)
{
if(to->isImmutable()) {
if(from==to) return;
throw std::invalid_argument("Convert.copyUnion destination is immutable");
}
if(from==to) return;
if(!isCopyUnionCompatible(from->getUnion(), to->getUnion())) {
throw std::invalid_argument("Illegal copyUnion");
}
PVFieldPtr fromValue = from->get();
if (from->getUnion()->isVariant())
{
if (fromValue.get() == 0)
to->set(PVFieldPtr());
else
to->set(getPVDataCreate()->createPVField(fromValue)); // clone value // TODO
}
else
{
if (fromValue.get() == 0)
to->select(PVUnion::UNDEFINED_INDEX);
else
copy(fromValue, to->select(from->getSelectedIndex()));
}
}
bool Convert::isCopyStructureArrayCompatible(
StructureArrayConstPtr const &from, StructureArrayConstPtr const &to)
{
@@ -403,6 +491,25 @@ void Convert::copyStructureArray(
to->replace(from->view());
}
bool Convert::isCopyUnionArrayCompatible(
UnionArrayConstPtr const &from, UnionArrayConstPtr const &to)
{
UnionConstPtr xxx = from->getUnion();
UnionConstPtr yyy = to->getUnion();
return isCopyUnionCompatible(xxx,yyy);
}
void Convert::copyUnionArray(
PVUnionArrayPtr const & from, PVUnionArrayPtr const & to)
{
if(from==to) {
return;
} else if(to->isImmutable()) {
throw std::invalid_argument("Convert.copyUnionArray destination is immutable");
}
to->replace(from->view());
}
void Convert::newLine(StringBuilder buffer, int indentLevel)
{
*buffer += "\n";

View File

@@ -56,7 +56,7 @@ struct ScalarArrayHashFunction {
struct StructureHashFunction {
size_t operator() (const Structure& /*structure*/) const { return 0; }
// TODO
// TODO hash
// final int PRIME = 31;
// return PRIME * Arrays.hashCode(fieldNames) + Arrays.hashCode(fields);
};
@@ -934,7 +934,7 @@ FieldConstPtr FieldCreate::deserialize(ByteBuffer* buffer, DeserializableControl
if (code == -1)
return FieldConstPtr();
int typeCode = code & 0xE0;
int typeCode = code & 0xEF;
bool notArray = ((code & 0x10) == 0);
if (notArray)
{

View File

@@ -446,6 +446,14 @@ PVFieldPtr PVDataCreate::createPVField(FieldConstPtr const & field)
StructureArrayConstPtr xx = static_pointer_cast<const StructureArray>(field);
return createPVStructureArray(xx);
}
case union_: {
UnionConstPtr xx = static_pointer_cast<const Union>(field);
return createPVUnion(xx);
}
case unionArray: {
UnionArrayConstPtr xx = static_pointer_cast<const UnionArray>(field);
return createPVUnionArray(xx);
}
}
throw std::logic_error("PVDataCreate::createPVField should never get here");
}
@@ -482,6 +490,21 @@ PVFieldPtr PVDataCreate::createPVField(PVFieldPtr const & fieldToClone)
getConvert()->copyStructureArray(from, to);
return to;
}
case union_:
{
PVUnionPtr pvUnion
= static_pointer_cast<PVUnion>(fieldToClone);
return createPVUnion(pvUnion);
}
case unionArray:
{
PVUnionArrayPtr from
= static_pointer_cast<PVUnionArray>(fieldToClone);
UnionArrayConstPtr unionArray = from->getUnionArray();
PVUnionArrayPtr to = createPVUnionArray(unionArray);
getConvert()->copyUnionArray(from, to);
return to;
}
}
throw std::logic_error("PVDataCreate::createPVField should never get here");
}
@@ -614,6 +637,28 @@ PVStructurePtr PVDataCreate::createPVStructure(
return PVStructurePtr(new PVStructure(structure));
}
PVUnionArrayPtr PVDataCreate::createPVUnionArray(
UnionArrayConstPtr const & unionArray)
{
return PVUnionArrayPtr(new PVUnionArray(unionArray));
}
PVUnionPtr PVDataCreate::createPVUnion(
UnionConstPtr const & punion)
{
return PVUnionPtr(new PVUnion(punion));
}
PVUnionPtr PVDataCreate::createPVVariantUnion()
{
return PVUnionPtr(new PVUnion(getFieldCreate()->createVariantUnion()));
}
PVUnionArrayPtr PVDataCreate::createPVVariantUnionArray()
{
return PVUnionArrayPtr(new PVUnionArray(getFieldCreate()->createVariantUnionArray()));
}
PVStructurePtr PVDataCreate::createPVStructure(
StringArray const & fieldNames,PVFieldPtrArray const & pvFields)
{
@@ -629,6 +674,7 @@ PVStructurePtr PVDataCreate::createPVStructure(PVStructurePtr const & structToCl
{
FieldConstPtrArray field;
if(structToClone==0) {
// is this correct?!
FieldConstPtrArray fields(0);
StringArray fieldNames(0);
StructureConstPtr structure = fieldCreate->createStructure(fieldNames,fields);
@@ -640,6 +686,14 @@ PVStructurePtr PVDataCreate::createPVStructure(PVStructurePtr const & structToCl
return pvStructure;
}
PVUnionPtr PVDataCreate::createPVUnion(PVUnionPtr const & unionToClone)
{
PVUnionPtr punion(new PVUnion(unionToClone->getUnion()));
// set cloned value
punion->set(unionToClone->getSelectedIndex(), createPVField(unionToClone->get()));
return punion;
}
PVDataCreatePtr PVDataCreate::getPVDataCreate()
{
static PVDataCreatePtr pvDataCreate;

View File

@@ -265,7 +265,9 @@ void PVField::computeOffset(const PVField * pvField) {
switch(field->getType()) {
case scalar:
case scalarArray:
case structureArray:{
case structureArray:
case union_:
case unionArray: {
nextOffset++;
pvField->fieldOffset = offset;
pvField->nextFieldOffset = nextOffset;
@@ -295,7 +297,9 @@ void PVField::computeOffset(const PVField * pvField,size_t offset) {
switch(field->getType()) {
case scalar:
case scalarArray:
case structureArray: {
case structureArray:
case union_:
case unionArray: {
nextOffset++;
pvSubField->fieldOffset = offset;
pvSubField->nextFieldOffset = nextOffset;

View File

@@ -38,6 +38,8 @@ PVDoublePtr PVStructure::nullPVDouble;
PVStringPtr PVStructure::nullPVString;
PVStructurePtr PVStructure::nullPVStructure;
PVStructureArrayPtr PVStructure::nullPVStructureArray;
PVUnionPtr PVStructure::nullPVUnion;
PVUnionArrayPtr PVStructure::nullPVUnionArray;
PVScalarArrayPtr PVStructure::nullPVScalarArray;
static PVFieldPtr findSubField(
@@ -520,6 +522,24 @@ PVStructurePtr PVStructure::getStructureField(String const &fieldName)
return nullPVStructure;
}
PVUnionPtr PVStructure::getUnionField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVUnion;
}
if(pvField->getField()->getType()==union_) {
return std::tr1::static_pointer_cast<PVUnion>(pvField);
}
String message("fieldName ");
message += fieldName + " does not have type union ";
this->message(message, errorMessage);
return nullPVUnion;
}
PVScalarArrayPtr PVStructure::getScalarArrayField(
String const &fieldName,ScalarType elementType)
{
@@ -569,6 +589,25 @@ PVStructureArrayPtr PVStructure::getStructureArrayField(
return nullPVStructureArray;
}
PVUnionArrayPtr PVStructure::getUnionArrayField(
String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVUnionArray;
}
if(pvField->getField()->getType()==unionArray) {
return std::tr1::static_pointer_cast<PVUnionArray>(pvField);
}
String message("fieldName ");
message += fieldName + " does not have type unionArray ";
this->message(message, errorMessage);
return nullPVUnionArray;
}
String PVStructure::getExtendsStructureName() const
{
return extendsStructureName;

View File

@@ -0,0 +1,208 @@
/*PVUnion.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mse
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <vector>
#include <pv/pvData.h>
#include <pv/pvIntrospect.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/serializeHelper.h>
using std::tr1::static_pointer_cast;
using std::size_t;
namespace epics { namespace pvData {
int32 PVUnion::UNDEFINED_INDEX = -1;
PVDataCreatePtr PVUnion::pvDataCreate = getPVDataCreate();
PVUnion::PVUnion(UnionConstPtr const & unionPtr)
: PVField(unionPtr),
unionPtr(unionPtr),
selector(UNDEFINED_INDEX),
value(),
variant(unionPtr->isVariant())
{
}
PVUnion::~PVUnion()
{
}
UnionConstPtr PVUnion::getUnion() const
{
return unionPtr;
}
PVFieldPtr PVUnion::get() const
{
return value;
}
int32 PVUnion::getSelectedIndex() const
{
return selector;
}
String PVUnion::getSelectedFieldName() const
{
// no name for undefined and for variant unions
if (selector == UNDEFINED_INDEX)
return String();
else
return unionPtr->getFieldName(selector);
}
PVFieldPtr PVUnion::select(int32 index)
{
// no change
if (selector == index)
return value;
if (index == UNDEFINED_INDEX)
{
selector = UNDEFINED_INDEX;
value.reset();
return value;
}
else if (variant)
throw std::invalid_argument("index out of bounds");
else if (index < 0 || index > static_cast<int32>(unionPtr->getFields().size()))
throw std::invalid_argument("index out of bounds");
FieldConstPtr field = unionPtr->getField(index);
selector = index;
value = pvDataCreate->createPVField(field);
return value;
}
PVFieldPtr PVUnion::select(String const & fieldName)
{
int32 index = variant ? -1 : unionPtr->getFieldIndex(fieldName);
if (index == -1)
throw std::invalid_argument("no such fieldName");
return select(index);
}
void PVUnion::set(PVFieldPtr const & value)
{
set(selector, value);
}
void PVUnion::set(int32 index, PVFieldPtr const & value)
{
if (variant && index != UNDEFINED_INDEX)
throw std::invalid_argument("index out of bounds");
else if (!variant)
{
if (index == UNDEFINED_INDEX)
{
// for undefined index we accept only null values
if (value.get())
throw std::invalid_argument("non-null value for index == UNDEFINED_INDEX");
}
else if (index < 0 || index > static_cast<int32>(unionPtr->getFields().size()))
throw std::invalid_argument("index out of bounds");
// value type must match
if (value->getField() != unionPtr->getField(index))
throw std::invalid_argument("selected field and its introspection data do not match");
}
selector = index;
this->value = value;
}
void PVUnion::set(String const & fieldName, PVFieldPtr const & value)
{
int32 index = variant ? -1 : unionPtr->getFieldIndex(fieldName);
if (index == -1)
throw std::invalid_argument("no such fieldName");
set(index, value);
}
void PVUnion::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const
{
if (variant)
{
// write introspection data
if (value.get() == 0)
pbuffer->put((int8)-1);
else
{
pflusher->cachedSerialize(value->getField(), pbuffer);
value->serialize(pbuffer, pflusher);
}
}
else
{
// write selector value
SerializeHelper::writeSize(selector, pbuffer, pflusher);
// write value, no value for UNDEFINED_INDEX
if (selector != UNDEFINED_INDEX)
value->serialize(pbuffer, pflusher);
}
}
void PVUnion::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol)
{
if (variant)
{
FieldConstPtr field = pcontrol->cachedDeserialize(pbuffer);
if (field.get())
{
value = pvDataCreate->createPVField(field);
value->deserialize(pbuffer, pcontrol);
}
else
value.reset();
}
else
{
selector = SerializeHelper::readSize(pbuffer, pcontrol);
if (selector != UNDEFINED_INDEX)
{
FieldConstPtr field = unionPtr->getField(selector);
value = pvDataCreate->createPVField(field);
value->deserialize(pbuffer, pcontrol);
}
else
value.reset();
}
}
std::ostream& PVUnion::dumpValue(std::ostream& o) const
{
o << format::indent() << getUnion()->getID() << ' ' << getFieldName() << std::endl;
{
format::indent_scope s(o);
PVFieldPtr fieldField = get();
if (fieldField.get() == NULL)
o << format::indent() << "(none)" << std::endl;
else
{
Type type = fieldField->getField()->getType();
if (type == scalar || type == scalarArray)
o << format::indent() << fieldField->getField()->getID() << ' ' << fieldField->getFieldName() << ' ' << *(fieldField.get()) << std::endl;
else
o << *(fieldField.get());
}
}
return o;
}
}}

View File

@@ -0,0 +1,212 @@
/*PVUnionArray.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/serializeHelper.h>
using std::tr1::static_pointer_cast;
using std::size_t;
namespace epics { namespace pvData {
size_t PVUnionArray::append(size_t number)
{
svector data(reuse());
data.resize(data.size()+number);
UnionConstPtr punion = unionArray->getUnion();
for(svector::reverse_iterator it = data.rbegin(); number; ++it, --number)
*it = getPVDataCreate()->createPVUnion(punion);
size_t newLength = data.size();
const_svector cdata(freeze(data));
swap(cdata);
return newLength;
}
bool PVUnionArray::remove(size_t offset,size_t number)
{
if(number==0)
return true;
else if(offset+number>getLength())
return false;
svector vec(reuse());
size_t length = vec.size();
for(size_t i = offset; i+number < length; i++) {
vec[i].swap(vec[i + number]);
}
vec.resize(length - number);
const_svector cdata(freeze(vec));
swap(cdata);
return true;
}
void PVUnionArray::compress() {
svector vec(reuse()); // TODO: check for first NULL before realloc
size_t length = vec.size();
size_t newLength = 0;
for(size_t i=0; i<length; i++) {
if(vec[i].get()!=NULL) {
newLength++;
continue;
}
// find first non 0
size_t notNull = 0;
for(size_t j=i+1;j<length;j++) {
if(vec[j].get()!=NULL) {
notNull = j;
break;
}
}
if(notNull!=0) {
vec[i] = vec[notNull];
vec[notNull].reset();
newLength++;
continue;
}
break;
}
vec.resize(newLength);
const_svector cdata(freeze(vec));
swap(cdata);
}
void PVUnionArray::setCapacity(size_t capacity)
{
if(this->isCapacityMutable()) {
const_svector value;
swap(value);
if(value.capacity()<capacity) {
svector mvalue(thaw(value));
mvalue.reserve(capacity);
value = freeze(mvalue);
}
swap(value);
}
}
void PVUnionArray::setLength(size_t length)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
const_svector value;
swap(value);
if(length == value.size()) {
// nothing
} else if(length < value.size()) {
value.slice(0, length);
} else {
svector mvalue(thaw(value));
mvalue.resize(length);
value = freeze(mvalue);
}
swap(value);
}
void PVUnionArray::swap(const_svector &other)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
value.swap(other);
}
void PVUnionArray::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
serialize(pbuffer, pflusher, 0, getLength());
}
void PVUnionArray::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
svector data(reuse());
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
data.resize(size);
UnionConstPtr punion = unionArray->getUnion();
for(size_t i = 0; i<size; i++) {
pcontrol->ensureData(1);
size_t temp = pbuffer->getByte();
if(temp==0) {
data[i].reset();
}
else {
if(data[i].get()==NULL) {
data[i] = getPVDataCreate()->createPVUnion(punion);
}
data[i]->deserialize(pbuffer, pcontrol);
}
}
replace(freeze(data)); // calls postPut()
}
void PVUnionArray::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const {
const_svector temp(view());
temp.slice(offset, count);
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
for(size_t i = 0; i<count; i++) {
if(pbuffer->getRemaining()<1)
pflusher->flushSerializeBuffer();
if(temp[i].get()==NULL) {
pbuffer->putByte(0);
}
else {
pbuffer->putByte(1);
temp[i]->serialize(pbuffer, pflusher);
}
}
}
std::ostream& PVUnionArray::dumpValue(std::ostream& o) const
{
o << format::indent() << getUnionArray()->getID() << ' ' << getFieldName() << std::endl;
size_t length = getLength();
if (length > 0)
{
format::indent_scope s(o);
for (size_t i = 0; i < length; i++)
dumpValue(o, i);
}
return o;
}
std::ostream& PVUnionArray::dumpValue(std::ostream& o, std::size_t index) const
{
const_svector temp(view());
if(index<temp.size())
o << temp[index].get();
return o;
}
}}

View File

@@ -22,10 +22,10 @@ namespace epics { namespace pvData {
namespace TypeFunc {
static const char* names[] = {
"scalar", "scalarArray", "structure", "structureArray",
"scalar", "scalarArray", "structure", "structureArray", "union", "unionArray"
};
const char* name(Type t) {
if (t<int(pvBoolean) || t>int(pvString))
if (t<int(scalar) || t>int(unionArray))
THROW_EXCEPTION2(std::invalid_argument, "logic error unknown Type");
return names[t];
}

View File

@@ -44,7 +44,13 @@ void PrinterBase::endStructure(const PVStructure&) {}
void PrinterBase::beginStructureArray(const PVStructureArray&) {}
void PrinterBase::endStructureArray(const PVStructureArray&) {}
void PrinterBase::encodeScalar(const PVScalar& pv) {}
void PrinterBase::beginUnion(const PVUnion&) {}
void PrinterBase::endUnion(const PVUnion&) {}
void PrinterBase::beginUnionArray(const PVUnionArray&) {}
void PrinterBase::endUnionArray(const PVUnionArray&) {}
void PrinterBase::encodeScalar(const PVScalar&) {}
void PrinterBase::encodeArray(const PVScalarArray&) {}
@@ -81,6 +87,14 @@ void PrinterBase::impl_print(const PVField& pv)
endStructureArray(*static_cast<const PVStructureArray *>(inprog.back()));
break;
case union_:
endUnion(*static_cast<const PVUnion *>(inprog.back()));
break;
case unionArray:
endUnionArray(*static_cast<const PVUnionArray *>(inprog.back()));
break;
default:
assert(false); // oops!
return;
@@ -129,6 +143,35 @@ void PrinterBase::impl_print(const PVField& pv)
todo.push_back(it->get());
}
todo.push_back(marker);
break;
}
case union_: {
const PVUnion &fld = *static_cast<const PVUnion*>(next);
inprog.push_back(next);
beginUnion(fld);
PVFieldPtr val = fld.get();
if (val.get()) // TODO print "(none)" ?
todo.push_back(val.get());
todo.push_back(marker);
break;
}
case unionArray: {
const PVUnionArray &fld = *static_cast<const PVUnionArray*>(next);
PVUnionArray::const_svector vals(fld.view());
inprog.push_back(next);
beginUnionArray(fld);
for(PVUnionArray::const_svector::const_iterator it=vals.begin();
it!=vals.end(); ++it)
{
todo.push_back(it->get());
}
todo.push_back(marker);
break;
}
@@ -168,6 +211,25 @@ void PrinterPlain::beginStructureArray(const PVStructureArray& pv)
void PrinterPlain::endStructureArray(const PVStructureArray&) {ilvl--;}
void PrinterPlain::beginUnion(const PVUnion& pv)
{
indentN(S(), ilvl);
S() << pv.getUnion()->getID() << " " << pv.getFieldName() << std::endl;
ilvl++;
}
void PrinterPlain::endUnion(const PVUnion&) {ilvl--;}
void PrinterPlain::beginUnionArray(const PVUnionArray& pv)
{
indentN(S(), ilvl);
S() << pv.getUnionArray()->getID() << " "
<< pv.getFieldName() << "[] ";
ilvl++;
}
void PrinterPlain::endUnionArray(const PVUnionArray&) {ilvl--;}
void PrinterPlain::encodeScalar(const PVScalar& pv)
{
indentN(S(), ilvl);

View File

@@ -30,6 +30,8 @@ bool operator==(const Scalar&, const Scalar&);
bool operator==(const ScalarArray&, const ScalarArray&);
bool operator==(const Structure&, const Structure&);
bool operator==(const StructureArray&, const StructureArray&);
bool operator==(const Union&, const Union&);
bool operator==(const UnionArray&, const UnionArray&);
static inline bool operator!=(const Field& a, const Field& b)
{return !(a==b);}
@@ -41,6 +43,10 @@ static inline bool operator!=(const Structure& a, const Structure& b)
{return !(a==b);}
static inline bool operator!=(const StructureArray& a, const StructureArray& b)
{return !(a==b);}
static inline bool operator!=(const Union& a, const Union& b)
{return !(a==b);}
static inline bool operator!=(const UnionArray& a, const UnionArray& b)
{return !(a==b);}
/**
@@ -291,6 +297,38 @@ public:
*/
void copyStructureArray(
PVStructureArrayPtr const & from, PVStructureArrayPtr const & to);
/**
* Are from and to valid arguments for copyUnion.
* They are only compatible if they have the same Union description.
* @param from from union.
* @param to union.
* @return (false,true) If the arguments (are not, are) compatible.
*/
bool isCopyUnionCompatible(
UnionConstPtr const & from, UnionConstPtr const & to);
/**
* Copy from a union pv to another union pv.
* NOTE: Only compatible nodes are copied.
* @param from The source.
* @param to The destination.
* @throws std::invalid_argument if the arguments are not compatible.
*/
void copyUnion(PVUnionPtr const & from, PVUnionPtr const & to);
/**
* Are from and to valid for copyUnionArray.
* @param from The from UnionArray.
* @param to The to UnionArray.
* @return (false,true) If the arguments (are not, are) compatible.
*/
bool isCopyUnionArrayCompatible(
UnionArrayConstPtr const & from, UnionArrayConstPtr const & to);
/**
* Copy from a union array to another union array.
* @param from The source array.
* @param to The destination array.
*/
void copyUnionArray(
PVUnionArrayPtr const & from, PVUnionArrayPtr const & to);
/**
* Convert a PV to a <byte>.
* @param pv a PV

View File

@@ -25,6 +25,12 @@ protected:
virtual void beginStructureArray(const PVStructureArray&);
virtual void endStructureArray(const PVStructureArray&);
virtual void beginUnion(const PVUnion&);
virtual void endUnion(const PVUnion&);
virtual void beginUnionArray(const PVUnionArray&);
virtual void endUnionArray(const PVUnionArray&);
virtual void encodeScalar(const PVScalar&);
virtual void encodeArray(const PVScalarArray&);
virtual void encodeNull();
@@ -46,6 +52,12 @@ protected:
virtual void beginStructureArray(const PVStructureArray&);
virtual void endStructureArray(const PVStructureArray&);
virtual void beginUnion(const PVUnion&);
virtual void endUnion(const PVUnion&);
virtual void beginUnionArray(const PVUnionArray&);
virtual void endUnionArray(const PVUnionArray&);
virtual void encodeScalar(const PVScalar&);
virtual void encodeArray(const PVScalarArray&);
virtual void encodeNull();

View File

@@ -108,6 +108,9 @@ class PVScalarArray;
class PVStructure;
class PVUnion;
template<typename T> class PVScalarValue;
template<typename T> class PVValueArray;
@@ -164,6 +167,29 @@ typedef std::tr1::shared_ptr<PVStructureArray> PVStructureArrayPtr;
typedef std::vector<PVStructureArrayPtr> PVStructureArrayPtrArray;
typedef std::tr1::shared_ptr<PVStructureArrayPtrArray> PVStructureArrayPtrArrayPtr;
/**
* typedef for a pointer to a PVUnion.
*/
typedef std::tr1::shared_ptr<PVUnion> PVUnionPtr;
/**
* typedef for a pointer to a array of pointer to PVUnion.
*/
typedef std::vector<PVUnionPtr> PVUnionPtrArray;
typedef std::vector<PVUnionPtr>::iterator PVUnionPtrArray_iterator;
typedef std::vector<PVUnionPtr>::const_iterator PVUnionPtrArray_const__iterator;
/**
* typedef for a pointer to a PVUnionArray.
*/
typedef PVValueArray<PVUnionPtr> PVUnionArray;
typedef std::tr1::shared_ptr<PVUnionArray> PVUnionArrayPtr;
typedef std::vector<PVUnionArrayPtr> PVUnionArrayPtrArray;
typedef std::tr1::shared_ptr<PVUnionArrayPtrArray> PVUnionArrayPtrArrayPtr;
class PVDataCreate;
typedef std::tr1::shared_ptr<PVDataCreate> PVDataCreatePtr;
/**
* This class provides auxillary information about a PVField.
* Each item is stored as a PVScalar.
@@ -890,6 +916,12 @@ public:
* @return Pointer to the field of null if a field with that name and type does not exist.
*/
PVStructurePtr getStructureField(String const &fieldName) ;
/**
* Get a union field with the specified name.
* @param fieldName The name of the field to get.
* @return Pointer to the field of null if a field with that name and type does not exist.
*/
PVUnionPtr getUnionField(String const &fieldName) ;
/**
* Get a scalarArray field with the specified name.
* @param fieldName The name of the field to get.
@@ -904,6 +936,12 @@ public:
* @return Pointer to the field of null if a field with that name and type does not exist.
*/
PVStructureArrayPtr getStructureArrayField(String const &fieldName) ;
/**
* Get a unionArray field with the specified name.
* @param fieldName The name of the field to get.
* @return Pointer to the field of null if a field with that name and type does not exist.
*/
PVUnionArrayPtr getUnionArrayField(String const &fieldName) ;
/**
* Get the name if this structure extends another structure.
* @return The string which may be null.
@@ -976,6 +1014,8 @@ private:
static PVStringPtr nullPVString;
static PVStructurePtr nullPVStructure;
static PVStructureArrayPtr nullPVStructureArray;
static PVUnionPtr nullPVUnion;
static PVUnionArrayPtr nullPVUnionArray;
static PVScalarArrayPtr nullPVScalarArray;
PVFieldPtrArray pvFields;
@@ -984,6 +1024,142 @@ private:
friend class PVDataCreate;
};
class PVUnion : public PVField
{
public:
POINTER_DEFINITIONS(PVUnion);
/**
* Destructor
*/
virtual ~PVUnion();
typedef PVUnion & reference;
typedef const PVUnion & const_reference;
/**
* Undefined index.
* Default value upon PVUnion construction. Can be set by the user.
* Corresponds to {@code null} value.
*/
static int32 UNDEFINED_INDEX;
/**
* Get the introspection interface
* @return The interface.
*/
UnionConstPtr getUnion() const;
/**
* Get the {@code PVField} value stored in the field.
* @return {@code PVField} value of field, {@code null} if {@code getSelectedIndex() == UNDEFINED_INDEX}.
*/
PVFieldPtr get() const;
// TODO dynamic vs static cast?
template<typename PVT>
std::tr1::shared_ptr<PVT> get() const {
return std::tr1::static_pointer_cast<PVT>(get());
}
/**
* Select field (set index) and get the field at the index.
* @param index index of the field to select.
* @return corresponding PVField (of undetermined value), {@code null} if {@code index == UNDEFINED_INDEX}.
* @throws {@code std::invalid_argument} if index is invalid (out of range).
*/
PVFieldPtr select(int32 index);
// TODO dynamic vs static cast?
template<typename PVT>
std::tr1::shared_ptr<PVT> select(int32 index) {
return std::tr1::static_pointer_cast<PVT>(select(index));
}
/**
* Select field (set index) and get the field by given name.
* @param fieldName the name of the field to select.
* @return corresponding PVField (of undetermined value).
* @throws {@code std::invalid_argument} if field does not exist.
*/
PVFieldPtr select(String const & fieldName);
// TODO dynamic vs static cast?
template<typename PVT>
std::tr1::shared_ptr<PVT> select(String const & fieldName) {
return std::tr1::static_pointer_cast<PVT>(select(fieldName));
}
/**
* Get selected field index.
* @return selected field index.
*/
int32 getSelectedIndex() const;
/**
* Get selected field name.
* @return selected field name, empty string if field does not exist.
*/
String getSelectedFieldName() const;
/**
* Set the {@code PVField} (by reference!) as selected field.
* If a value is not a valid union field an {@code std::invalid_argument} exception is thrown.
* @param value the field to set.
*/
void set(PVFieldPtr const & value);
/**
* Set the {@code PVField} (by reference!) as field at given index.
* If a value is not a valid union field an {@code std::invalid_argument} exception is thrown.
* Use {@code select(int)} to put by value.
* @param index index of a field to put.
* @param value the field to set.
* @see #select(int)
*/
void set(int32 index, PVFieldPtr const & value);
/**
* Set the {@code PVField} (by reference!) as field by given name.
* If a value is not a valid union field an {@code std::invalid_argument} exception is thrown.
* Use {@code select(String)} to put by value.
* @param fieldName Name of the field to put.
* @param value the field to set.
* @see #select(String)
*/
void set(String const & fieldName, PVFieldPtr const & value);
/**
* Serialize.
* @param pbuffer The byte buffer.
* @param pflusher Interface to call when buffer is full.
*/
virtual void serialize(
ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
/**
* Deserialize
* @param pbuffer The byte buffer.
* @param pflusher Interface to call when buffer is empty.
*/
virtual void deserialize(
ByteBuffer *pbuffer,DeserializableControl *pflusher);
/**
* Constructor
* @param punion The introspection interface.
*/
PVUnion(UnionConstPtr const & punion);
virtual std::ostream& dumpValue(std::ostream& o) const;
private:
friend class PVDataCreate;
static PVDataCreatePtr pvDataCreate;
UnionConstPtr unionPtr;
int32 selector;
PVFieldPtr value;
bool variant;
};
namespace detail {
// adaptor to allow epics::pvData::shared_vector to hold a reference
// to a shared_ptr<std::vector<> >
@@ -1301,6 +1477,105 @@ private:
friend class PVDataCreate;
};
/**
* This is provided by code that calls get.
*/
typedef PVArrayData<PVUnionPtr> UnionArrayData;
/**
* Data class for a unionArray
*/
template<>
class PVValueArray<PVUnionPtr> : public detail::PVVectorStorage<PVUnionPtr,PVArray>
{
typedef detail::PVVectorStorage<PVUnionPtr,PVArray> base_t;
public:
POINTER_DEFINITIONS(PVUnionArray);
typedef PVUnionPtr value_type;
typedef PVUnionPtr* pointer;
typedef const PVUnionPtr* const_pointer;
typedef PVArrayData<PVUnionPtr> ArrayDataType;
typedef std::vector<PVUnionPtr> vector;
typedef const std::vector<PVUnionPtr> const_vector;
typedef std::tr1::shared_ptr<vector> shared_vector;
typedef PVUnionArray &reference;
typedef const PVUnionArray& const_reference;
//TODO: full namespace can be removed along with local typedef 'shared_vector'
typedef ::epics::pvData::shared_vector<PVUnionPtr> svector;
typedef ::epics::pvData::shared_vector<const PVUnionPtr> const_svector;
/**
* Destructor
*/
virtual ~PVValueArray() {}
virtual size_t getLength() const {return value.size();}
virtual size_t getCapacity() const {return value.capacity();}
/**
* Set the array capacity.
* @param capacity The length.
*/
virtual void setCapacity(size_t capacity);
/**
* Set the array length.
* @param length The length.
*/
virtual void setLength(std::size_t length);
/**
* Get the introspection interface
* @return The interface.
*/
UnionArrayConstPtr getUnionArray() const {return unionArray;}
/**
* Append new elements to the end of the array.
* @param number The number of elements to add.
* @return the new length of the array.
*/
virtual std::size_t append(std::size_t number);
/**
* Remove elements from the array.
* @param offset The offset of the first element to remove.
* @param number The number of elements to remove.
* @return (false,true) if the elements were removed.
*/
virtual bool remove(std::size_t offset,std::size_t number);
/**
* Compress. This removes all null elements from the array.
*/
virtual void compress();
virtual const_svector view() const { return value; }
virtual void swap(const_svector &other);
virtual void replace(const const_svector &other) {
value = other;
PVField::postPut();
}
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const;
virtual void deserialize(ByteBuffer *buffer,
DeserializableControl *pflusher);
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
virtual std::ostream& dumpValue(std::ostream& o) const;
virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
protected:
PVValueArray(UnionArrayConstPtr const & unionArray)
:base_t(unionArray)
,unionArray(unionArray)
{}
private:
UnionArrayConstPtr unionArray;
const_svector value;
friend class PVDataCreate;
};
/**
* Definitions for the various scalarArray types.
*/
@@ -1352,8 +1627,6 @@ typedef PVArrayData<String> StringArrayData;
typedef PVValueArray<String> PVStringArray;
typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
class PVDataCreate;
typedef std::tr1::shared_ptr<PVDataCreate> PVDataCreatePtr;
/**
* This is a singlton class for creating data instances.
*/
@@ -1439,6 +1712,36 @@ public:
* @return The PVStructure implementation.
*/
PVStructurePtr createPVStructure(PVStructurePtr const & structToClone);
/**
* Create an implementation of an array with union elements.
* @param unionArray The introspection interface.
* All elements share the same introspection interface.
* @return The PVUnionArray implementation.
*/
PVUnionArrayPtr createPVUnionArray(UnionArrayConstPtr const & unionArray);
/**
* Create implementation for PVUnion.
* @param union The introspection interface.
* @return The PVUnion implementation
*/
PVUnionPtr createPVUnion(UnionConstPtr const & punion);
/**
* Create implementation for PVUnion.
* @param unionToClone A union. Each subfield is cloned and added to the newly created union.
* @return The PVUnion implementation.
*/
PVUnionPtr createPVUnion(PVUnionPtr const & unionToClone);
/**
* Create variant union implementation.
* @return The variant PVUnion implementation.
*/
PVUnionPtr createPVVariantUnion();
/**
* Create variant union array implementation.
* @return The variant PVUnionArray implementation.
*/
PVUnionArrayPtr createPVVariantUnionArray();
private:
PVDataCreate();
FieldCreatePtr fieldCreate;

View File

@@ -140,7 +140,7 @@ void serializationTest(PVFieldPtr const & field) {
}
void testEquals() {
testDiag("Testing equals...");
testDiag("Testing equals..."); // and non-initialized
PVDataCreatePtr factory = getPVDataCreate();
testOk1(factory.get()!=NULL);
@@ -167,6 +167,59 @@ void testEquals() {
PVStructureArrayPtr structureArray1 = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure1->getStructure()));
PVStructureArrayPtr structureArray2 = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure2->getStructure()));
testOk1((*structureArray1)==(*structureArray2));
// variant union
PVUnionPtr variantUnion1 = factory->createPVVariantUnion();
PVUnionPtr variantUnion2 = factory->createPVVariantUnion();
testOk1((*variantUnion1)==(*variantUnion2));
variantUnion1->set(structure1);
variantUnion2->set(structure1);
testOk1((*variantUnion1)==(*variantUnion2));
variantUnion2->set(structureArray1);
testOk1((*variantUnion1)!=(*variantUnion2));
// variant union array
PVUnionArrayPtr variantUnionArray1 = factory->createPVVariantUnionArray();
PVUnionArrayPtr variantUnionArray2 = factory->createPVVariantUnionArray();
testOk1((*variantUnionArray1)==(*variantUnionArray2));
// union
UnionConstPtr punion = getFieldCreate()->createFieldBuilder()->
add("double", pvDouble)->
add("double2", pvDouble)->
addStructureArray("nested")->
setId("nestedId")->
add("short", pvShort)->
add("long", pvLong)->
createNested()->
addArray("intArray", pvInt)->
createUnion();
PVUnionPtr union1 = factory->createPVUnion(punion);
PVUnionPtr union2 = factory->createPVUnion(punion);
testOk1((*union1)==(*union2));
union1->select<PVDouble>("double")->put(1.2);
union2->select<PVDouble>("double")->put(1.2);
testOk1((*union1)==(*union2));
union2->select<PVDouble>("double")->put(2.2);
testOk1((*union1)!=(*union2));
union2->select<PVDouble>("double2")->put(1.2);
testOk1((*union1)!=(*union2));
union2->select("nested");
testOk1((*union1)!=(*union2));
testOk1((*union1)!=(*variantUnion2));
PVUnionArrayPtr unionArray1 = factory->createPVUnionArray(getFieldCreate()->createUnionArray(punion));
PVUnionArrayPtr unionArray2 = factory->createPVUnionArray(getFieldCreate()->createUnionArray(punion));
testOk1((*unionArray1)==(*unionArray2));
testOk1((*variantUnionArray1)!=(*unionArray2));
}
template<typename PVT>
@@ -322,32 +375,6 @@ void testArray() {
testArrayType<PVStringArray>(sdata, NELEMENTS(sdata));
}
void testNonInitialized() {
testDiag("Testing non-initialized...");
PVDataCreatePtr factory = getPVDataCreate();
testOk1(factory.get()!=NULL);
// be sure all is covered
for (int i = pvBoolean; i < pvString; i++)
{
ScalarType scalarType = static_cast<ScalarType>(i);
PVScalarPtr scalar = factory->createPVScalar(scalarType);
serializationTest(scalar);
PVScalarArrayPtr array = factory->createPVScalarArray(scalarType);
serializationTest(array);
}
// and a structure
PVStructurePtr structure = factory->createPVStructure(getStandardField()->timeStamp());
serializationTest(structure);
// and a structure array
PVStructureArrayPtr structureArray = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure->getStructure()));
serializationTest(structureArray);
}
void testStructure() {
testDiag("Testing structure...");
@@ -371,6 +398,196 @@ void testStructure() {
serializationTest(pvStructure);
}
template<typename PVT>
std::tr1::shared_ptr<PVT> createPVScalar()
{
return std::tr1::static_pointer_cast<PVT>(
getPVDataCreate()->createPVScalar(PVT::typeCode)
);
}
template<typename PVAT>
std::tr1::shared_ptr<PVAT> createPVScalarArray()
{
return std::tr1::static_pointer_cast<PVAT>(
getPVDataCreate()->createPVScalarArray(PVAT::typeCode)
);
}
void testUnion() {
testDiag("Testing union...");
PVDataCreatePtr factory = getPVDataCreate();
testOk1(factory.get()!=NULL);
PVDoublePtr doubleValue = createPVScalar<PVDouble>();
PVIntPtr intValue = createPVScalar<PVInt>();
testDiag("\tVariant union test");
PVUnionPtr variant = factory->createPVVariantUnion();
testOk1(variant.get()!=NULL);
testOk1(PVUnion::UNDEFINED_INDEX == variant->getSelectedIndex());
testOk1("" == variant->getSelectedFieldName());
serializationTest(variant);
variant->set(doubleValue);
testOk1(doubleValue.get() == variant->get().get());
testOk1(PVUnion::UNDEFINED_INDEX == variant->getSelectedIndex());
testOk1("" == variant->getSelectedFieldName());
serializationTest(variant);
variant->set(intValue);
testOk1(intValue.get() == variant->get().get());
testOk1(PVUnion::UNDEFINED_INDEX == variant->getSelectedIndex());
testOk1("" == variant->getSelectedFieldName());
serializationTest(variant);
variant->set(PVUnion::UNDEFINED_INDEX, doubleValue);
testOk1(doubleValue.get() == variant->get().get());
testOk1(PVUnion::UNDEFINED_INDEX == variant->getSelectedIndex());
variant->set(PVFieldPtr());
testOk1(NULL == variant->get().get());
testDiag("\tVariant union array test");
PVUnionArrayPtr variantArray = factory->createPVVariantUnionArray();
testOk1(variantArray.get()!=NULL);
variantArray->setLength(6);
PVUnionArray::svector data;
PVUnionPtr u = factory->createPVVariantUnion();
data.push_back(u);
u = factory->createPVVariantUnion();
u->set(factory->createPVStructure(getStandardField()->timeStamp()));
data.push_back(u);
u = factory->createPVVariantUnion();
u->set(factory->createPVStructure(getStandardField()->control()));
data.push_back(u);
data.push_back(PVUnionPtr());
variantArray->replace(freeze(data));
serializationTest(variantArray);
testDiag("\tVariant union test");
UnionConstPtr punion = getFieldCreate()->createFieldBuilder()->
add("doubleValue", pvDouble)->
add("intValue", pvInt)->
createUnion();
u = factory->createPVUnion(punion);
testOk1(NULL!=u.get());
// null union test
testOk1(NULL==u->get().get());
testOk1(PVUnion::UNDEFINED_INDEX == u->getSelectedIndex());
testOk1("" == u->getSelectedFieldName());
serializationTest(u);
u->select<PVDouble>("doubleValue")->put(12);
testOk1(12 == u->get<PVDouble>()->get());
testOk1(0 == u->getSelectedIndex());
testOk1("doubleValue" == u->getSelectedFieldName());
serializationTest(u);
u->select<PVInt>("intValue")->put(543);
testOk1(543 == u->get<PVInt>()->get());
testOk1(1 == u->getSelectedIndex());
testOk1("intValue" == u->getSelectedFieldName());
serializationTest(u);
u->select<PVInt>(1)->put(5432);
testOk1(5432 == u->get<PVInt>()->get());
serializationTest(u);
testOk1(NULL==u->select(PVUnion::UNDEFINED_INDEX).get());
testOk1(NULL==u->get().get());
testOk1(PVUnion::UNDEFINED_INDEX == u->getSelectedIndex());
testOk1("" == u->getSelectedFieldName());
serializationTest(u);
u->set("doubleValue", doubleValue);
testOk1(doubleValue.get() == u->get().get());
testOk1(0 == u->getSelectedIndex());
serializationTest(u);
try
{
u->set(1, doubleValue);
testFail("field type does not match, but set allowed");
}
catch (std::invalid_argument& ia)
{
// expected
testPass("PVUnion.set(int32, PVFieldPtr const&) field type does not match test");
}
try
{
u->select(120);
testFail("index out of bounds allowed");
}
catch (std::invalid_argument& ia)
{
// expected
testPass("PVUnion.select(int32) index out of bounds test");
}
try
{
u->select(-2);
testFail("index out of bounds allowed");
}
catch (std::invalid_argument& ia)
{
// expected
testPass("PVUnion.select(int32) index out of bounds test");
}
try
{
u->set(120, doubleValue);
testFail("index out of bounds allowed");
}
catch (std::invalid_argument& ia)
{
// expected
testPass("PVUnion.set(int32, PVFieldPtr const&) index out of bounds test");
}
testDiag("\tUnion array test");
PVUnionArrayPtr unionArray = factory->createPVUnionArray(getFieldCreate()->createUnionArray(punion));
testOk1(unionArray.get()!=NULL);
unionArray->setLength(6);
data.clear();
u = factory->createPVUnion(punion);
data.push_back(u);
u = factory->createPVUnion(punion);
u->select<PVDouble>(0)->put(12);
data.push_back(u);
u = factory->createPVUnion(punion);
u->select<PVInt>(1)->put(421);
data.push_back(u);
data.push_back(PVUnionPtr());
unionArray->replace(freeze(data));
serializationTest(unionArray);
}
void testStructureArray() {
testDiag("Testing structure array...");
@@ -461,7 +678,7 @@ void testIntrospectionSerialization()
ScalarArrayConstPtr array = factory->createScalarArray(scalarType);
serializatioTest(array);
}
}
// and a structure
StructureConstPtr structure = getStandardField()->timeStamp();
@@ -470,7 +687,31 @@ void testIntrospectionSerialization()
// and a structure array
StructureArrayConstPtr structureArray = factory->createStructureArray(structure);
serializatioTest(structureArray);
}
// variant union
UnionConstPtr variant = factory->createVariantUnion();
serializatioTest(variant);
// variant array union
UnionArrayConstPtr variantArray = factory->createVariantUnionArray();
serializatioTest(variantArray);
// union
UnionConstPtr punion = factory->createFieldBuilder()->
add("double", pvDouble)->
addStructureArray("nested")->
setId("nestedId")->
add("short", pvShort)->
add("long", pvLong)->
createNested()->
addArray("intArray", pvInt)->
createUnion();
serializatioTest(punion);
// union array
UnionArrayConstPtr punionArray = factory->createUnionArray(punion);
serializatioTest(punionArray);
}
void testStringCopy() {
String s1 = "abc";
@@ -483,7 +724,7 @@ void testStringCopy() {
MAIN(testSerialization) {
testPlan(175);
testPlan(213);
flusher = new SerializableControlImpl();
control = new DeserializableControlImpl();
@@ -493,12 +734,13 @@ MAIN(testSerialization) {
testIntrospectionSerialization();
testEquals();
testNonInitialized();
testScalar();
testArray();
testStructure();
testStructureArray();
testUnion();
delete buffer;