Files
pvData/pvDataApp/factory/PVUnion.cpp
2013-11-07 14:12:26 +01:00

209 lines
5.1 KiB
C++

/*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;
}
}}