782 lines
23 KiB
C++
782 lines
23 KiB
C++
/*PVDataCreateFactory.cpp*/
|
|
/*
|
|
* Copyright information and license terms for this software can be
|
|
* found in the file LICENSE that is included with the distribution
|
|
*/
|
|
/**
|
|
* @author mrk
|
|
*/
|
|
|
|
#include <cstddef>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
#include <cstdio>
|
|
|
|
#include <epicsMutex.h>
|
|
#include <epicsThread.h>
|
|
|
|
#define epicsExportSharedSymbols
|
|
#include <pv/lock.h>
|
|
#include <pv/pvIntrospect.h>
|
|
#include <pv/pvData.h>
|
|
#include <pv/factory.h>
|
|
#include <pv/serializeHelper.h>
|
|
#include <pv/reftrack.h>
|
|
|
|
using std::tr1::static_pointer_cast;
|
|
using std::size_t;
|
|
using std::string;
|
|
using std::min;
|
|
|
|
namespace epics { namespace pvData {
|
|
|
|
|
|
template<> const ScalarType PVBoolean::typeCode = pvBoolean;
|
|
template<> const ScalarType PVByte::typeCode = pvByte;
|
|
template<> const ScalarType PVShort::typeCode = pvShort;
|
|
template<> const ScalarType PVInt::typeCode = pvInt;
|
|
template<> const ScalarType PVLong::typeCode = pvLong;
|
|
template<> const ScalarType PVUByte::typeCode = pvUByte;
|
|
template<> const ScalarType PVUShort::typeCode = pvUShort;
|
|
template<> const ScalarType PVUInt::typeCode = pvUInt;
|
|
template<> const ScalarType PVULong::typeCode = pvULong;
|
|
template<> const ScalarType PVFloat::typeCode = pvFloat;
|
|
template<> const ScalarType PVDouble::typeCode = pvDouble;
|
|
template<> const ScalarType PVScalarValue<string>::typeCode = pvString;
|
|
|
|
template<> const ScalarType PVBooleanArray::typeCode = pvBoolean;
|
|
template<> const ScalarType PVByteArray::typeCode = pvByte;
|
|
template<> const ScalarType PVShortArray::typeCode = pvShort;
|
|
template<> const ScalarType PVIntArray::typeCode = pvInt;
|
|
template<> const ScalarType PVLongArray::typeCode = pvLong;
|
|
template<> const ScalarType PVUByteArray::typeCode = pvUByte;
|
|
template<> const ScalarType PVUShortArray::typeCode = pvUShort;
|
|
template<> const ScalarType PVUIntArray::typeCode = pvUInt;
|
|
template<> const ScalarType PVULongArray::typeCode = pvULong;
|
|
template<> const ScalarType PVFloatArray::typeCode = pvFloat;
|
|
template<> const ScalarType PVDoubleArray::typeCode = pvDouble;
|
|
template<> const ScalarType PVStringArray::typeCode = pvString;
|
|
|
|
|
|
template<typename T>
|
|
PVScalarValue<T>::~PVScalarValue() {}
|
|
|
|
template<typename T>
|
|
std::ostream& PVScalarValue<T>::dumpValue(std::ostream& o) const
|
|
{
|
|
return o << get();
|
|
}
|
|
|
|
template<typename T>
|
|
void PVScalarValue<T>::operator>>=(T& value) const
|
|
{
|
|
value = get();
|
|
}
|
|
|
|
template<typename T>
|
|
void PVScalarValue<T>::operator<<=(typename storage_t::arg_type value)
|
|
{
|
|
put(value);
|
|
}
|
|
|
|
template<typename T>
|
|
void PVScalarValue<T>::assign(const PVScalar& scalar)
|
|
{
|
|
if(isImmutable())
|
|
throw std::invalid_argument("destination is immutable");
|
|
copyUnchecked(scalar);
|
|
}
|
|
|
|
template<typename T>
|
|
void PVScalarValue<T>::copy(const PVScalar& from)
|
|
{
|
|
assign(from);
|
|
}
|
|
|
|
template<typename T>
|
|
void PVScalarValue<T>::copyUnchecked(const PVScalar& from)
|
|
{
|
|
if(this==&from)
|
|
return;
|
|
T result;
|
|
from.getAs((void*)&result, typeCode);
|
|
put(result);
|
|
}
|
|
|
|
template<typename T>
|
|
void PVScalarValue<T>::serialize(ByteBuffer *pbuffer,
|
|
SerializableControl *pflusher) const {
|
|
pflusher->ensureBuffer(sizeof(T));
|
|
pbuffer->put(storage.value);
|
|
}
|
|
|
|
template<>
|
|
void PVScalarValue<std::string>::serialize(ByteBuffer *pbuffer,
|
|
SerializableControl *pflusher) const {
|
|
SerializeHelper::serializeString(storage.value, pbuffer, pflusher);
|
|
}
|
|
|
|
template<typename T>
|
|
void PVScalarValue<T>::deserialize(ByteBuffer *pbuffer,
|
|
DeserializableControl *pflusher)
|
|
{
|
|
pflusher->ensureData(sizeof(T));
|
|
storage.value = pbuffer->GET(T);
|
|
}
|
|
|
|
template<>
|
|
void PVScalarValue<std::string>::deserialize(ByteBuffer *pbuffer,
|
|
DeserializableControl *pflusher)
|
|
{
|
|
storage.value = SerializeHelper::deserializeString(pbuffer, pflusher);
|
|
// TODO: check for violations of maxLength?
|
|
}
|
|
|
|
PVString::PVString(ScalarConstPtr const & scalar)
|
|
: PVScalarValue<std::string>(scalar)
|
|
{
|
|
BoundedStringConstPtr boundedString = std::tr1::dynamic_pointer_cast<const BoundedString>(scalar);
|
|
if (boundedString.get())
|
|
storage.maxLength = boundedString->getMaximumLength();
|
|
else
|
|
storage.maxLength = 0;
|
|
}
|
|
|
|
std::ostream& PVString::dumpValue(std::ostream& o) const
|
|
{
|
|
o<<maybeQuote(get());
|
|
return o;
|
|
}
|
|
|
|
/* mixing overrides (virtual functions) and overloads (different argument lists) is fun...
|
|
* we override all overloads to avoid the "hides overloaded virtual function" warning from clang.
|
|
* In this case we don't need/want to, so just delegate to the base class.
|
|
*/
|
|
void PVString::serialize(ByteBuffer *pbuffer,
|
|
SerializableControl *pflusher) const
|
|
{PVScalarValue<std::string>::serialize(pbuffer, pflusher);}
|
|
|
|
void PVString::serialize(ByteBuffer *pbuffer,
|
|
SerializableControl *pflusher, size_t offset, size_t count) const
|
|
{
|
|
// check bounds
|
|
const size_t length = storage.value.length();
|
|
/*if (offset < 0) offset = 0;
|
|
else*/ if (offset > length) offset = length;
|
|
//if (count < 0) count = length;
|
|
|
|
const size_t maxCount = length - offset;
|
|
if (count > maxCount)
|
|
count = maxCount;
|
|
|
|
// write
|
|
SerializeHelper::serializeSubstring(storage.value, offset, count, pbuffer, pflusher);
|
|
}
|
|
|
|
void PVArray::checkLength(size_t len) const
|
|
{
|
|
Array::ArraySizeType type = getArray()->getArraySizeType();
|
|
if (type != Array::variable)
|
|
{
|
|
size_t size = getArray()->getMaximumCapacity();
|
|
if (type == Array::fixed && len != size)
|
|
throw std::invalid_argument("invalid length for a fixed size array");
|
|
else if (type == Array::bounded && len > size)
|
|
throw std::invalid_argument("new array capacity too large for a bounded size array");
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
PVValueArray<T>::PVValueArray(ScalarArrayConstPtr const & scalarArray)
|
|
:base_t(scalarArray)
|
|
,value()
|
|
|
|
{}
|
|
|
|
PVValueArray<PVStructurePtr>::PVValueArray(StructureArrayConstPtr const & structureArray)
|
|
:base_t(structureArray)
|
|
,structureArray(structureArray)
|
|
|
|
{}
|
|
|
|
PVValueArray<PVUnionPtr>::PVValueArray(UnionArrayConstPtr const & unionArray)
|
|
:base_t(unionArray)
|
|
,unionArray(unionArray)
|
|
{}
|
|
|
|
template<typename T>
|
|
PVValueArray<T>::~PVValueArray() {}
|
|
|
|
template<typename T>
|
|
ArrayConstPtr PVValueArray<T>::getArray() const
|
|
{
|
|
return std::tr1::static_pointer_cast<const Array>(this->getField());
|
|
}
|
|
|
|
template<typename T>
|
|
std::ostream& PVValueArray<T>::dumpValue(std::ostream& o) const
|
|
{
|
|
const_svector v(this->view());
|
|
typename const_svector::const_iterator it(v.begin()),
|
|
end(v.end());
|
|
o << '[';
|
|
if(it!=end) {
|
|
o << print_cast(*it++);
|
|
for(; it!=end; ++it)
|
|
o << ',' << print_cast(*it);
|
|
|
|
}
|
|
return o << ']';
|
|
}
|
|
|
|
template<>
|
|
std::ostream& PVValueArray<std::string>::dumpValue(std::ostream& o, size_t index) const
|
|
{
|
|
return o << maybeQuote(this->view().at(index));
|
|
}
|
|
|
|
template<>
|
|
std::ostream& PVValueArray<std::string>::dumpValue(std::ostream& o) const
|
|
{
|
|
const_svector v(this->view());
|
|
const_svector::const_iterator it(v.begin()),
|
|
end(v.end());
|
|
o << '[';
|
|
if(it!=end) {
|
|
o << maybeQuote(*it++);
|
|
for(; it!=end; ++it)
|
|
o << ", " << maybeQuote(*it);
|
|
|
|
}
|
|
return o << ']';
|
|
}
|
|
|
|
template<typename T>
|
|
std::ostream& PVValueArray<T>::dumpValue(std::ostream& o, size_t index) const
|
|
{
|
|
return o << print_cast(this->view().at(index));
|
|
}
|
|
|
|
template<typename T>
|
|
void PVValueArray<T>::setCapacity(size_t capacity)
|
|
{
|
|
if(this->isCapacityMutable()) {
|
|
this->checkLength(capacity);
|
|
value.reserve(capacity);
|
|
}
|
|
else
|
|
THROW_EXCEPTION2(std::logic_error, "capacity immutable");
|
|
}
|
|
|
|
template<typename T>
|
|
void PVValueArray<T>::setLength(size_t length)
|
|
{
|
|
if(this->isImmutable())
|
|
THROW_EXCEPTION2(std::logic_error, "immutable");
|
|
|
|
if (length == value.size())
|
|
return;
|
|
|
|
this->checkLength(length);
|
|
|
|
if (length < value.size())
|
|
value.slice(0, length);
|
|
else
|
|
value.resize(length);
|
|
}
|
|
|
|
template<typename T>
|
|
void PVValueArray<T>::replace(const const_svector& next)
|
|
{
|
|
this->checkLength(next.size());
|
|
|
|
value = next;
|
|
this->postPut();
|
|
}
|
|
|
|
template<typename T>
|
|
void PVValueArray<T>::swap(const_svector &other)
|
|
{
|
|
if (this->isImmutable())
|
|
THROW_EXCEPTION2(std::logic_error, "immutable");
|
|
|
|
// no checkLength call here
|
|
|
|
value.swap(other);
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
void PVValueArray<T>::serialize(ByteBuffer *pbuffer,
|
|
SerializableControl *pflusher) const {
|
|
serialize(pbuffer, pflusher, 0, this->getLength());
|
|
}
|
|
|
|
template<typename T>
|
|
void PVValueArray<T>::deserialize(ByteBuffer *pbuffer,
|
|
DeserializableControl *pcontrol) {
|
|
|
|
size_t size = this->getArray()->getArraySizeType() == Array::fixed ?
|
|
this->getArray()->getMaximumCapacity() :
|
|
SerializeHelper::readSize(pbuffer, pcontrol);
|
|
|
|
svector nextvalue(thaw(value));
|
|
nextvalue.resize(size); // TODO: avoid copy of stuff we will then overwrite
|
|
|
|
T* cur = nextvalue.data();
|
|
|
|
// try to avoid deserializing from the buffer
|
|
// this is only possible if we do not need to do endian-swapping
|
|
if (!pbuffer->reverse<T>())
|
|
if (pcontrol->directDeserialize(pbuffer, (char*)cur, size, sizeof(T)))
|
|
{
|
|
// inform about the change?
|
|
PVField::postPut();
|
|
return;
|
|
}
|
|
|
|
// retrieve value from the buffer
|
|
size_t remaining = size;
|
|
while(remaining) {
|
|
const size_t have_bytes = pbuffer->getRemaining();
|
|
|
|
// correctly rounds down in an element is partially received
|
|
const size_t available = have_bytes/sizeof(T);
|
|
|
|
if(available == 0) {
|
|
// get at least one element
|
|
pcontrol->ensureData(sizeof(T));
|
|
continue;
|
|
}
|
|
|
|
const size_t n2read = std::min(remaining, available);
|
|
|
|
pbuffer->getArray(cur, n2read);
|
|
cur += n2read;
|
|
remaining -= n2read;
|
|
}
|
|
value = freeze(nextvalue);
|
|
// TODO !!!
|
|
// inform about the change?
|
|
PVField::postPut();
|
|
}
|
|
|
|
template<typename T>
|
|
void PVValueArray<T>::serialize(ByteBuffer *pbuffer,
|
|
SerializableControl *pflusher, size_t offset, size_t count) const
|
|
{
|
|
//TODO: avoid incrementing the ref counter...
|
|
const_svector temp(value);
|
|
temp.slice(offset, count);
|
|
count = temp.size();
|
|
|
|
ArrayConstPtr array = this->getArray();
|
|
if (array->getArraySizeType() != Array::fixed)
|
|
SerializeHelper::writeSize(count, pbuffer, pflusher);
|
|
else if (count != array->getMaximumCapacity())
|
|
throw std::length_error("fixed array cannot be partially serialized");
|
|
|
|
const T* cur = temp.data();
|
|
|
|
// try to avoid copying into the buffer
|
|
// this is only possible if we do not need to do endian-swapping
|
|
if (!pbuffer->reverse<T>())
|
|
if (pflusher->directSerialize(pbuffer, (const char*)cur, count, sizeof(T)))
|
|
return;
|
|
|
|
while(count) {
|
|
const size_t empty = pbuffer->getRemaining();
|
|
const size_t space_for = empty/sizeof(T);
|
|
|
|
if(space_for==0) {
|
|
pflusher->flushSerializeBuffer();
|
|
// Can we be certain that more space is now free???
|
|
// If not then we spinnnnnnnnn
|
|
continue;
|
|
}
|
|
|
|
const size_t n2send = std::min(count, space_for);
|
|
|
|
pbuffer->putArray(cur, n2send);
|
|
cur += n2send;
|
|
count -= n2send;
|
|
}
|
|
}
|
|
|
|
// specializations for string
|
|
|
|
template<>
|
|
void PVValueArray<string>::deserialize(ByteBuffer *pbuffer,
|
|
DeserializableControl *pcontrol) {
|
|
|
|
size_t size = this->getArray()->getArraySizeType() == Array::fixed ?
|
|
this->getArray()->getMaximumCapacity() :
|
|
SerializeHelper::readSize(pbuffer, pcontrol);
|
|
|
|
svector nextvalue(thaw(value));
|
|
|
|
// Decide if we must re-allocate
|
|
if(size > nextvalue.size() || !nextvalue.unique())
|
|
nextvalue.resize(size);
|
|
else if(size < nextvalue.size())
|
|
nextvalue.slice(0, size);
|
|
|
|
|
|
string * pvalue = nextvalue.data();
|
|
for(size_t i = 0; i<size; i++) {
|
|
pvalue[i] = SerializeHelper::deserializeString(pbuffer,
|
|
pcontrol);
|
|
}
|
|
value = freeze(nextvalue);
|
|
// inform about the change?
|
|
postPut();
|
|
}
|
|
|
|
template<>
|
|
void PVValueArray<string>::serialize(ByteBuffer *pbuffer,
|
|
SerializableControl *pflusher, size_t offset, size_t count) const {
|
|
|
|
const_svector temp(value);
|
|
temp.slice(offset, count);
|
|
|
|
// TODO if fixed count == getArray()->getMaximumCapacity()
|
|
if (this->getArray()->getArraySizeType() != Array::fixed)
|
|
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
|
|
|
|
const string * pvalue = temp.data();
|
|
for(size_t i = 0; i<temp.size(); i++) {
|
|
SerializeHelper::serializeString(pvalue[i], pbuffer, pflusher);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void PVValueArray<T>::_getAsVoid(epics::pvData::shared_vector<const void>& out) const
|
|
{
|
|
out = static_shared_vector_cast<const void>(this->view());
|
|
}
|
|
|
|
template<typename T>
|
|
void PVValueArray<T>::_putFromVoid(const epics::pvData::shared_vector<const void>& in)
|
|
{
|
|
this->replace(shared_vector_convert<const T>(in));
|
|
}
|
|
|
|
// Factory
|
|
|
|
PVDataCreate::PVDataCreate()
|
|
: fieldCreate(getFieldCreate())
|
|
{ }
|
|
|
|
PVFieldPtr PVDataCreate::createPVField(FieldConstPtr const & field)
|
|
{
|
|
switch(field->getType()) {
|
|
case scalar: {
|
|
ScalarConstPtr xx = static_pointer_cast<const Scalar>(field);
|
|
return createPVScalar(xx);
|
|
}
|
|
case scalarArray: {
|
|
ScalarArrayConstPtr xx = static_pointer_cast<const ScalarArray>(field);
|
|
return createPVScalarArray(xx);
|
|
}
|
|
case structure: {
|
|
StructureConstPtr xx = static_pointer_cast<const Structure>(field);
|
|
return createPVStructure(xx);
|
|
}
|
|
case structureArray: {
|
|
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");
|
|
}
|
|
|
|
PVFieldPtr PVDataCreate::createPVField(PVFieldPtr const & fieldToClone)
|
|
{
|
|
switch(fieldToClone->getField()->getType()) {
|
|
case scalar:
|
|
{
|
|
PVScalarPtr pvScalar = static_pointer_cast<PVScalar>(fieldToClone);
|
|
return createPVScalar(pvScalar);
|
|
}
|
|
case scalarArray:
|
|
{
|
|
PVScalarArrayPtr pvScalarArray
|
|
= static_pointer_cast<PVScalarArray>(fieldToClone);
|
|
return createPVScalarArray(pvScalarArray);
|
|
}
|
|
case structure:
|
|
{
|
|
PVStructurePtr pvStructure
|
|
= static_pointer_cast<PVStructure>(fieldToClone);
|
|
StringArray const & fieldNames = pvStructure->getStructure()->getFieldNames();
|
|
PVFieldPtrArray const & pvFieldPtrArray = pvStructure->getPVFields();
|
|
return createPVStructure(fieldNames,pvFieldPtrArray);
|
|
}
|
|
case structureArray:
|
|
{
|
|
PVStructureArrayPtr from
|
|
= static_pointer_cast<PVStructureArray>(fieldToClone);
|
|
StructureArrayConstPtr structureArray = from->getStructureArray();
|
|
PVStructureArrayPtr to = createPVStructureArray(
|
|
structureArray);
|
|
to->copyUnchecked(*from);
|
|
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);
|
|
to->copyUnchecked(*from);
|
|
return to;
|
|
}
|
|
}
|
|
throw std::logic_error("PVDataCreate::createPVField should never get here");
|
|
}
|
|
|
|
PVScalarPtr PVDataCreate::createPVScalar(ScalarConstPtr const & scalar)
|
|
{
|
|
ScalarType scalarType = scalar->getScalarType();
|
|
switch(scalarType) {
|
|
case pvBoolean:
|
|
return PVScalarPtr(new PVBoolean(scalar));
|
|
case pvByte:
|
|
return PVScalarPtr(new PVByte(scalar));
|
|
case pvShort:
|
|
return PVScalarPtr(new PVShort(scalar));
|
|
case pvInt:
|
|
return PVScalarPtr(new PVInt(scalar));
|
|
case pvLong:
|
|
return PVScalarPtr(new PVLong(scalar));
|
|
case pvUByte:
|
|
return PVScalarPtr(new PVUByte(scalar));
|
|
case pvUShort:
|
|
return PVScalarPtr(new PVUShort(scalar));
|
|
case pvUInt:
|
|
return PVScalarPtr(new PVUInt(scalar));
|
|
case pvULong:
|
|
return PVScalarPtr(new PVULong(scalar));
|
|
case pvFloat:
|
|
return PVScalarPtr(new PVFloat(scalar));
|
|
case pvDouble:
|
|
return PVScalarPtr(new PVDouble(scalar));
|
|
case pvString:
|
|
return PVScalarPtr(new PVString(scalar));
|
|
}
|
|
throw std::logic_error("PVDataCreate::createPVScalar should never get here");
|
|
}
|
|
|
|
PVScalarPtr PVDataCreate::createPVScalar(ScalarType scalarType)
|
|
{
|
|
ScalarConstPtr scalar = fieldCreate->createScalar(scalarType);
|
|
return createPVScalar(scalar);
|
|
}
|
|
|
|
|
|
PVScalarPtr PVDataCreate::createPVScalar(PVScalarPtr const & scalarToClone)
|
|
{
|
|
ScalarType scalarType = scalarToClone->getScalar()->getScalarType();
|
|
PVScalarPtr pvScalar = createPVScalar(scalarType);
|
|
pvScalar->copyUnchecked(*scalarToClone);
|
|
return pvScalar;
|
|
}
|
|
|
|
PVScalarArrayPtr PVDataCreate::createPVScalarArray(
|
|
ScalarArrayConstPtr const & scalarArray)
|
|
{
|
|
switch(scalarArray->getElementType()) {
|
|
case pvBoolean:
|
|
return PVScalarArrayPtr(new PVBooleanArray(scalarArray));
|
|
case pvByte:
|
|
return PVScalarArrayPtr(new PVByteArray(scalarArray));
|
|
case pvShort:
|
|
return PVScalarArrayPtr(new PVShortArray(scalarArray));
|
|
case pvInt:
|
|
return PVScalarArrayPtr(new PVIntArray(scalarArray));
|
|
case pvLong:
|
|
return PVScalarArrayPtr(new PVLongArray(scalarArray));
|
|
case pvUByte:
|
|
return PVScalarArrayPtr(new PVUByteArray(scalarArray));
|
|
case pvUShort:
|
|
return PVScalarArrayPtr(new PVUShortArray(scalarArray));
|
|
case pvUInt:
|
|
return PVScalarArrayPtr(new PVUIntArray(scalarArray));
|
|
case pvULong:
|
|
return PVScalarArrayPtr(new PVULongArray(scalarArray));
|
|
case pvFloat:
|
|
return PVScalarArrayPtr(new PVFloatArray(scalarArray));
|
|
case pvDouble:
|
|
return PVScalarArrayPtr(new PVDoubleArray(scalarArray));
|
|
case pvString:
|
|
return PVScalarArrayPtr(new PVStringArray(scalarArray));
|
|
}
|
|
throw std::logic_error("PVDataCreate::createPVScalarArray should never get here");
|
|
|
|
}
|
|
|
|
PVScalarArrayPtr PVDataCreate::createPVScalarArray(
|
|
ScalarType elementType)
|
|
{
|
|
ScalarArrayConstPtr scalarArray = fieldCreate->createScalarArray(elementType);
|
|
return createPVScalarArray(scalarArray);
|
|
}
|
|
|
|
PVScalarArrayPtr PVDataCreate::createPVScalarArray(
|
|
PVScalarArrayPtr const & arrayToClone)
|
|
{
|
|
PVScalarArrayPtr pvArray = createPVScalarArray(
|
|
arrayToClone->getScalarArray()->getElementType());
|
|
pvArray->assign(*arrayToClone.get());
|
|
return pvArray;
|
|
}
|
|
|
|
PVStructureArrayPtr PVDataCreate::createPVStructureArray(
|
|
StructureArrayConstPtr const & structureArray)
|
|
{
|
|
return PVStructureArrayPtr(new PVStructureArray(structureArray));
|
|
}
|
|
|
|
PVStructurePtr PVDataCreate::createPVStructure(
|
|
StructureConstPtr const & structure)
|
|
{
|
|
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(fieldCreate->createVariantUnion()));
|
|
}
|
|
|
|
PVUnionArrayPtr PVDataCreate::createPVVariantUnionArray()
|
|
{
|
|
return PVUnionArrayPtr(new PVUnionArray(fieldCreate->createVariantUnionArray()));
|
|
}
|
|
|
|
PVStructurePtr PVDataCreate::createPVStructure(
|
|
StringArray const & fieldNames,PVFieldPtrArray const & pvFields)
|
|
{
|
|
size_t num = fieldNames.size();
|
|
FieldConstPtrArray fields(num);
|
|
for (size_t i=0;i<num;i++) fields[i] = pvFields[i]->getField();
|
|
StructureConstPtr structure = fieldCreate->createStructure(fieldNames,fields);
|
|
PVStructurePtr pvStructure(new PVStructure(structure,pvFields));
|
|
return pvStructure;
|
|
}
|
|
|
|
PVStructurePtr PVDataCreate::createPVStructure(PVStructurePtr const & structToClone)
|
|
{
|
|
FieldConstPtrArray field;
|
|
if(!structToClone) {
|
|
// is this correct?!
|
|
FieldConstPtrArray fields(0);
|
|
StringArray fieldNames(0);
|
|
StructureConstPtr structure = fieldCreate->createStructure(fieldNames,fields);
|
|
return PVStructurePtr(new PVStructure(structure));
|
|
}
|
|
StructureConstPtr structure = structToClone->getStructure();
|
|
PVStructurePtr pvStructure(new PVStructure(structure));
|
|
pvStructure->copyUnchecked(*structToClone);
|
|
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;
|
|
}
|
|
|
|
namespace detail {
|
|
struct pvfield_factory {
|
|
PVDataCreatePtr pvDataCreate;
|
|
pvfield_factory() :pvDataCreate(new PVDataCreate()) {
|
|
registerRefCounter("PVField", &PVField::num_instances);
|
|
}
|
|
};
|
|
}
|
|
|
|
static detail::pvfield_factory* pvfield_factory_s;
|
|
static epicsThreadOnceId pvfield_factory_once = EPICS_THREAD_ONCE_INIT;
|
|
|
|
static void pvfield_factory_init(void*)
|
|
{
|
|
try {
|
|
pvfield_factory_s = new detail::pvfield_factory;
|
|
}catch(std::exception& e){
|
|
std::cerr<<"Error initializing getFieldCreate() : "<<e.what()<<"\n";
|
|
}
|
|
}
|
|
|
|
const PVDataCreatePtr& PVDataCreate::getPVDataCreate()
|
|
{
|
|
epicsThreadOnce(&pvfield_factory_once, &pvfield_factory_init, 0);
|
|
if(!pvfield_factory_s->pvDataCreate)
|
|
throw std::logic_error("getPVDataCreate() not initialized");
|
|
return pvfield_factory_s->pvDataCreate;
|
|
}
|
|
|
|
// explicitly instanciate to ensure that windows
|
|
// builds emit exported symbols for inline'd methods
|
|
template class PVScalarValue<boolean>;
|
|
template class PVScalarValue<int8>;
|
|
template class PVScalarValue<uint8>;
|
|
template class PVScalarValue<int16>;
|
|
template class PVScalarValue<uint16>;
|
|
template class PVScalarValue<int32>;
|
|
template class PVScalarValue<uint32>;
|
|
template class PVScalarValue<int64>;
|
|
template class PVScalarValue<uint64>;
|
|
template class PVScalarValue<float>;
|
|
template class PVScalarValue<double>;
|
|
template class PVScalarValue<std::string>;
|
|
template class PVValueArray<boolean>;
|
|
template class PVValueArray<int8>;
|
|
template class PVValueArray<uint8>;
|
|
template class PVValueArray<int16>;
|
|
template class PVValueArray<uint16>;
|
|
template class PVValueArray<int32>;
|
|
template class PVValueArray<uint32>;
|
|
template class PVValueArray<int64>;
|
|
template class PVValueArray<uint64>;
|
|
template class PVValueArray<float>;
|
|
template class PVValueArray<double>;
|
|
template class PVValueArray<std::string>;
|
|
|
|
}} // namespace epics::pvData
|
|
|
|
namespace std{
|
|
std::ostream& operator<<(std::ostream& o, const epics::pvData::PVField *ptr)
|
|
{
|
|
if(ptr) return o << *ptr;
|
|
return o << "nullptr";
|
|
}
|
|
}
|