New array API for PVValueArray using shared_vector<T>
* In PVScalarArray Add methods assign, getAs/putFrom, and copyOut/copyIn to allow get/put with implicit convert. assign() copys on PVScalarArray to another converting as necessary. If the types do not match then an allocate and convert is done. getAs/putFrom work with shared_vector<T> and can avoid a allocate and convert operation if the types match. copyOut/copyIn use plain C arrays will do either a copy if the types match, and a convert otherwise. No allocation is performed. * In PVValueArray<T> All array operations re-implemented in terms of two virtual methods virtual const shared_vector<T>& viewUnsafe() const; virtual void swap(shared_vector<T>&); Some convienence methods are also included: shared_vector<const T> view() const shared_vector<T> take() shared_vector<T> reuse() Deprecate get(...), put(...), and shareData(...) Remove getVector() and getSharedVector() Adjust DefaultPVArray accordingly
This commit is contained in:
@@ -196,51 +196,31 @@ public:
|
||||
typedef const std::vector<T> const_vector;
|
||||
typedef std::tr1::shared_ptr<vector> shared_vector;
|
||||
|
||||
typedef ::epics::pvData::shared_vector<T> svector;
|
||||
typedef ::epics::pvData::shared_vector<const T> const_svector;
|
||||
|
||||
DefaultPVArray(ScalarArrayConstPtr const & scalarArray);
|
||||
virtual ~DefaultPVArray();
|
||||
|
||||
virtual void setCapacity(size_t capacity);
|
||||
virtual void setLength(size_t length);
|
||||
virtual size_t get(size_t offset, size_t length, PVArrayData<T> &data) ;
|
||||
virtual size_t put(size_t offset,size_t length, const_pointer from,
|
||||
size_t fromOffset);
|
||||
virtual void shareData(
|
||||
std::tr1::shared_ptr<std::vector<T> > const & value,
|
||||
std::size_t capacity,
|
||||
std::size_t length);
|
||||
virtual pointer get() ;
|
||||
virtual pointer get() const ;
|
||||
virtual vector const & getVector() { return *value.get(); }
|
||||
virtual shared_vector const & getSharedVector(){return value;};
|
||||
|
||||
virtual const svector& viewUnsafe() const;
|
||||
virtual void swap(svector &other);
|
||||
|
||||
// from Serializable
|
||||
virtual void serialize(ByteBuffer *pbuffer,SerializableControl *pflusher) const;
|
||||
virtual void deserialize(ByteBuffer *pbuffer,DeserializableControl *pflusher);
|
||||
virtual void serialize(ByteBuffer *pbuffer,
|
||||
SerializableControl *pflusher, size_t offset, size_t count) const;
|
||||
private:
|
||||
shared_vector value;
|
||||
svector value;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T *DefaultPVArray<T>::get()
|
||||
{
|
||||
std::vector<T> *vec = value.get();
|
||||
T *praw = &((*vec)[0]);
|
||||
return praw;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *DefaultPVArray<T>::get() const
|
||||
{
|
||||
std::vector<T> *vec = value.get();
|
||||
T *praw = &((*vec)[0]);
|
||||
return praw;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
DefaultPVArray<T>::DefaultPVArray(ScalarArrayConstPtr const & scalarArray)
|
||||
: PVValueArray<T>(scalarArray),
|
||||
value(std::tr1::shared_ptr<std::vector<T> >(new std::vector<T>()))
|
||||
value()
|
||||
|
||||
{ }
|
||||
|
||||
@@ -251,101 +231,41 @@ DefaultPVArray<T>::~DefaultPVArray()
|
||||
template<typename T>
|
||||
void DefaultPVArray<T>::setCapacity(size_t capacity)
|
||||
{
|
||||
if(PVArray::getCapacity()==capacity) return;
|
||||
if(!PVArray::isCapacityMutable()) {
|
||||
std::string message("not capacityMutable");
|
||||
PVField::message(message, errorMessage);
|
||||
return;
|
||||
if(capacity>value.capacity()) {
|
||||
value.reserve(capacity);
|
||||
PVArray::setCapacityLength(value.capacity(), value.size());
|
||||
}
|
||||
size_t length = PVArray::getLength();
|
||||
if(length>capacity) length = capacity;
|
||||
size_t oldCapacity = PVArray::getCapacity();
|
||||
if(oldCapacity>capacity) {
|
||||
std::vector<T> array;
|
||||
array.reserve(capacity);
|
||||
array.resize(length);
|
||||
T * from = get();
|
||||
for (size_t i=0; i<length; i++) array[i] = from[i];
|
||||
value->swap(array);
|
||||
} else {
|
||||
value->reserve(capacity);
|
||||
}
|
||||
PVArray::setCapacityLength(capacity,length);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void DefaultPVArray<T>::setLength(size_t length)
|
||||
{
|
||||
if(PVArray::getLength()==length) return;
|
||||
size_t capacity = PVArray::getCapacity();
|
||||
if(length>capacity) {
|
||||
if(!PVArray::isCapacityMutable()) {
|
||||
std::string message("not capacityMutable");
|
||||
PVField::message(message, errorMessage);
|
||||
return;
|
||||
}
|
||||
setCapacity(length);
|
||||
}
|
||||
value->resize(length);
|
||||
PVArray::setCapacityLength(capacity,length);
|
||||
if(length == value.size())
|
||||
return;
|
||||
else if(length < value.size())
|
||||
value.slice(0, length);
|
||||
else
|
||||
value.resize(length);
|
||||
PVArray::setCapacityLength(value.capacity(), value.size());
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
const typename DefaultPVArray<T>::svector& DefaultPVArray<T>::viewUnsafe() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t DefaultPVArray<T>::get(size_t offset, size_t len, PVArrayData<T> &data)
|
||||
void DefaultPVArray<T>::swap(svector &other)
|
||||
{
|
||||
size_t n = len;
|
||||
size_t length = this->getLength();
|
||||
if(offset+len > length) {
|
||||
n = length-offset;
|
||||
//if(n<0) n = 0;
|
||||
}
|
||||
data.data = *value.get();
|
||||
data.offset = offset;
|
||||
return n;
|
||||
if(this->isImmutable())
|
||||
THROW_EXCEPTION2(std::logic_error,"Immutable");
|
||||
|
||||
value.swap(other);
|
||||
PVArray::setCapacityLength(value.capacity(), value.size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t DefaultPVArray<T>::put(size_t offset,size_t len,
|
||||
const_pointer from,size_t fromOffset)
|
||||
{
|
||||
if(PVField::isImmutable()) {
|
||||
PVField::message("field is immutable",errorMessage);
|
||||
return 0;
|
||||
}
|
||||
T * pvalue = get();
|
||||
if(from==pvalue) return len;
|
||||
if(len<1) return 0;
|
||||
size_t length = this->getLength();
|
||||
size_t capacity = this->getCapacity();
|
||||
if(offset+len > length) {
|
||||
size_t newlength = offset + len;
|
||||
if(newlength>capacity) {
|
||||
setCapacity(newlength);
|
||||
newlength = this->getCapacity();
|
||||
len = newlength - offset;
|
||||
if(len<=0) return 0;
|
||||
}
|
||||
length = newlength;
|
||||
setLength(length);
|
||||
}
|
||||
pvalue = get();
|
||||
for(size_t i=0;i<len;i++) {
|
||||
pvalue[i+offset] = from[i+fromOffset];
|
||||
}
|
||||
this->setLength(length);
|
||||
this->postPut();
|
||||
return len;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void DefaultPVArray<T>::shareData(
|
||||
std::tr1::shared_ptr<std::vector<T> > const & sharedValue,
|
||||
std::size_t capacity,
|
||||
std::size_t length)
|
||||
{
|
||||
value = sharedValue;
|
||||
PVArray::setCapacityLength(capacity,length);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
|
||||
@@ -357,93 +277,91 @@ template<typename T>
|
||||
void DefaultPVArray<T>::deserialize(ByteBuffer *pbuffer,
|
||||
DeserializableControl *pcontrol) {
|
||||
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
|
||||
// alignment if (size>0) { pcontrol->ensureData(sizeof(T)-1); pbuffer->align(sizeof(T)); }
|
||||
//if(size>=0) {
|
||||
// prepare array, if necessary
|
||||
if(size>this->getCapacity()) this->setCapacity(size);
|
||||
// set new length
|
||||
this->setLength(size);
|
||||
|
||||
// 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*)(get()), size, sizeof(T)))
|
||||
{
|
||||
// inform about the change?
|
||||
PVField::postPut();
|
||||
return;
|
||||
}
|
||||
value.resize(size); // TODO: avoid copy of stuff we will then overwrite
|
||||
|
||||
// retrieve value from the buffer
|
||||
size_t i = 0;
|
||||
T * pvalue = get();
|
||||
while(true) {
|
||||
/*
|
||||
size_t maxIndex = min(size-i, (int)(pbuffer->getRemaining()/sizeof(T)))+i;
|
||||
for(; i<maxIndex; i++)
|
||||
value[i] = pbuffer->get<T>();
|
||||
*/
|
||||
size_t maxCount = min(size-i, (pbuffer->getRemaining()/sizeof(T)));
|
||||
pbuffer->getArray(pvalue+i, maxCount);
|
||||
i += maxCount;
|
||||
|
||||
if(i<size)
|
||||
pcontrol->ensureData(sizeof(T)); // this is not OK since can exceen max local buffer (size-i)*sizeof(T));
|
||||
else
|
||||
break;
|
||||
}
|
||||
PVArray::setCapacityLength(value.capacity(), value.size());
|
||||
T* cur = value.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();
|
||||
//}
|
||||
// TODO null arrays (size == -1) not supported
|
||||
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) {
|
||||
size_t want = sizeof(T);
|
||||
if(remaining==1 && sizeof(T)>1) {
|
||||
// Need to wait for the last few bytes
|
||||
// of the final element.
|
||||
// available==0 implies have_bytes<sizeof(T)
|
||||
want = sizeof(T) - have_bytes;
|
||||
}
|
||||
// recv() at least one element, or remaining buffer
|
||||
pcontrol->ensureData(want);
|
||||
continue;
|
||||
}
|
||||
|
||||
const size_t n2read = std::min(remaining, available);
|
||||
|
||||
pbuffer->getArray(cur, n2read);
|
||||
cur += n2read;
|
||||
remaining -= n2read;
|
||||
}
|
||||
// inform about the change?
|
||||
PVField::postPut();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
|
||||
SerializableControl *pflusher, size_t offset, size_t count) const {
|
||||
// cache
|
||||
size_t length = this->getLength();
|
||||
SerializableControl *pflusher, size_t offset, size_t count) const
|
||||
{
|
||||
//TODO: avoid incrementing the ref counter...
|
||||
svector temp(value);
|
||||
temp.slice(offset, count);
|
||||
count = temp.size();
|
||||
|
||||
// check bounds
|
||||
/*if(offset<0)
|
||||
offset = 0;
|
||||
else*/ if(offset>length) offset = length;
|
||||
//if(count<0) count = length;
|
||||
|
||||
size_t maxCount = length-offset;
|
||||
if(count>maxCount) count = maxCount;
|
||||
|
||||
// write
|
||||
SerializeHelper::writeSize(count, pbuffer, pflusher);
|
||||
//if (count == 0) return; pcontrol->ensureData(sizeof(T)-1); pbuffer->align(sizeof(T));
|
||||
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
|
||||
|
||||
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*)(get()+offset), count, sizeof(T)))
|
||||
if (pflusher->directSerialize(pbuffer, (const char*)cur, count, sizeof(T)))
|
||||
return;
|
||||
|
||||
size_t end = offset+count;
|
||||
size_t i = offset;
|
||||
T * pvalue = const_cast<T *>(get());
|
||||
while(true) {
|
||||
|
||||
/*
|
||||
size_t maxIndex = min<int>(end-i, (int)(pbuffer->getRemaining()/sizeof(T)))+i;
|
||||
for(; i<maxIndex; i++)
|
||||
pbuffer->put<T>(value[i]);
|
||||
*/
|
||||
|
||||
size_t maxCount = min<int>(end-i, (int)(pbuffer->getRemaining()/sizeof(T)));
|
||||
pbuffer->putArray(pvalue+i, maxCount);
|
||||
i += maxCount;
|
||||
|
||||
if(i<end)
|
||||
while(count) {
|
||||
const size_t empty = pbuffer->getRemaining();
|
||||
const size_t space_for = empty/sizeof(T);
|
||||
|
||||
if(space_for==0) {
|
||||
pflusher->flushSerializeBuffer();
|
||||
else
|
||||
break;
|
||||
// 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;
|
||||
}
|
||||
|
||||
pflusher->flushSerializeBuffer();
|
||||
}
|
||||
|
||||
// specializations for String
|
||||
@@ -452,42 +370,36 @@ template<>
|
||||
void DefaultPVArray<String>::deserialize(ByteBuffer *pbuffer,
|
||||
DeserializableControl *pcontrol) {
|
||||
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
|
||||
//if(size>=0) {
|
||||
// prepare array, if necessary
|
||||
if(size>getCapacity()) setCapacity(size);
|
||||
// set new length
|
||||
setLength(size);
|
||||
// retrieve value from the buffer
|
||||
String * pvalue = get();
|
||||
for(size_t i = 0; i<size; i++) {
|
||||
pvalue[i] = SerializeHelper::deserializeString(pbuffer,
|
||||
pcontrol);
|
||||
}
|
||||
// inform about the change?
|
||||
postPut();
|
||||
//}
|
||||
// TODO null arrays (size == -1) not supported
|
||||
|
||||
// Decide if we must re-allocate
|
||||
if(size > value.size() || !value.unique())
|
||||
value.resize(size);
|
||||
else if(size < value.size())
|
||||
value.slice(0, size);
|
||||
|
||||
setCapacityLength(size, size);
|
||||
|
||||
|
||||
String * pvalue = value.data();
|
||||
for(size_t i = 0; i<size; i++) {
|
||||
pvalue[i] = SerializeHelper::deserializeString(pbuffer,
|
||||
pcontrol);
|
||||
}
|
||||
// inform about the change?
|
||||
postPut();
|
||||
}
|
||||
|
||||
template<>
|
||||
void DefaultPVArray<String>::serialize(ByteBuffer *pbuffer,
|
||||
SerializableControl *pflusher, size_t offset, size_t count) const {
|
||||
size_t length = getLength();
|
||||
|
||||
// check bounds
|
||||
/*if(offset<0)
|
||||
offset = 0;
|
||||
else*/ if(offset>length) offset = length;
|
||||
//if(count<0) count = length;
|
||||
svector temp(value);
|
||||
temp.slice(offset, count);
|
||||
|
||||
size_t maxCount = length-offset;
|
||||
if(count>maxCount) count = maxCount;
|
||||
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
|
||||
|
||||
// write
|
||||
SerializeHelper::writeSize(count, pbuffer, pflusher);
|
||||
size_t end = offset+count;
|
||||
String * pvalue = get();
|
||||
for(size_t i = offset; i<end; i++) {
|
||||
String * pvalue = temp.data();
|
||||
for(size_t i = 0; i<temp.size(); i++) {
|
||||
SerializeHelper::serializeString(pvalue[i], pbuffer, pflusher);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,15 @@
|
||||
*/
|
||||
#ifndef PVDATA_H
|
||||
#define PVDATA_H
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define USAGE_DEPRECATED __attribute__((deprecated))
|
||||
#define USAGE_ERROR(MSG) __attribute__((error(MSG)))
|
||||
#else
|
||||
#define USAGE_DEPRECATED
|
||||
#define USAGE_ERROR(MSG)
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
@@ -19,6 +28,7 @@
|
||||
#include <pv/pvIntrospect.h>
|
||||
#include <pv/requester.h>
|
||||
#include <pv/typeCast.h>
|
||||
#include <pv/sharedVector.h>
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
|
||||
@@ -657,22 +667,75 @@ public:
|
||||
*/
|
||||
const ScalarArrayConstPtr getScalarArray() const ;
|
||||
|
||||
/**
|
||||
* Fetch the current value and convert to the requeted type.
|
||||
*
|
||||
* A copy is made if the requested type does not match
|
||||
* the element type. If the types do match then
|
||||
* no copy is made.
|
||||
*/
|
||||
template<ScalarType ID>
|
||||
inline void getAs(typename ScalarTypeTraits<ID>::type* ptr,
|
||||
size_t count, size_t offset = 0) const
|
||||
inline void
|
||||
getAs(shared_vector<typename ScalarTypeTraits<ID>::type>& out) const
|
||||
{
|
||||
getAs(ID, (void*)ptr, count, offset);
|
||||
shared_vector<void> temp(static_shared_vector_cast<void>(out));
|
||||
getAs(ID, temp);
|
||||
out = static_shared_vector_cast<typename ScalarTypeTraits<ID>::type>(temp);
|
||||
}
|
||||
virtual void getAs(ScalarType, void*, size_t, size_t) const = 0;
|
||||
virtual void
|
||||
getAs(ScalarType, shared_vector<void>& out) const = 0;
|
||||
|
||||
/**
|
||||
* Assign the given value after conversion.
|
||||
*
|
||||
* A copy and element-wise conversion is are always performed.
|
||||
*/
|
||||
template<ScalarType ID>
|
||||
inline void putFrom(const typename ScalarTypeTraits<ID>::type* ptr,
|
||||
size_t count, size_t offset = 0)
|
||||
inline size_t copyOut(typename ScalarTypeTraits<ID>::type* inp, size_t len) const
|
||||
{
|
||||
putFrom(ID, (const void*)ptr, count, offset);
|
||||
return copyOut(ID, (void*)inp, len);
|
||||
}
|
||||
virtual void putFrom(ScalarType, const void*, size_t ,size_t) = 0;
|
||||
virtual size_t copyOut(ScalarType, void*, size_t) const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Assign the given value after conversion.
|
||||
*
|
||||
* A copy and element-wise conversion is performed unless
|
||||
* the element type of the PVScalarArray matches the
|
||||
* type of the provided data.
|
||||
* If the types do match then a new refernce to the provided
|
||||
* data is kept.
|
||||
*/
|
||||
template<ScalarType ID>
|
||||
inline void putFrom(const shared_vector<typename ScalarTypeTraits<ID>::type>& inp)
|
||||
{
|
||||
shared_vector<void> temp(static_shared_vector_cast<void>(inp));
|
||||
putFrom(ID, temp);
|
||||
}
|
||||
virtual void putFrom(ScalarType, const shared_vector<void>&) = 0;
|
||||
|
||||
/**
|
||||
* Assign the given value after conversion.
|
||||
*
|
||||
* A copy and element-wise conversion is are always performed.
|
||||
*/
|
||||
template<ScalarType ID>
|
||||
inline void copyIn(const typename ScalarTypeTraits<ID>::type* inp, size_t len)
|
||||
{
|
||||
copyIn(ID, (const void*)inp, len);
|
||||
}
|
||||
virtual void copyIn(ScalarType, const void*, size_t) = 0;
|
||||
|
||||
/**
|
||||
* Assign the given PVScalarArray's value.
|
||||
*
|
||||
* A copy and element-wise conversion is performed unless
|
||||
* the element type of the PVScalarArray matches the
|
||||
* type of the provided data.
|
||||
* If the types do match then a new refernce to the provided
|
||||
* data is kept.
|
||||
*/
|
||||
virtual void assign(PVScalarArray& pv) = 0;
|
||||
|
||||
protected:
|
||||
@@ -1016,6 +1079,19 @@ private:
|
||||
friend class PVDataCreate;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
// adaptor to allow epics::pvData::shared_vector to hold a reference
|
||||
// to a shared_ptr<std::vector<> >
|
||||
template<typename T>
|
||||
struct shared_ptr_vector_deletor {
|
||||
typedef std::tr1::shared_ptr<std::vector<T> > shared_vector;
|
||||
shared_vector vec;
|
||||
shared_ptr_vector_deletor(const shared_vector& v)
|
||||
:vec(v) {}
|
||||
void operator()(T*){vec.reset();}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class PVValueArray : public PVScalarArray {
|
||||
public:
|
||||
@@ -1023,12 +1099,19 @@ public:
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
|
||||
//TODO: full namespace can be removed along with local typedef 'shared_vector'
|
||||
typedef ::epics::pvData::shared_vector<T> svector;
|
||||
typedef ::epics::pvData::shared_vector<const T> const_svector;
|
||||
|
||||
// begin deprecated
|
||||
typedef PVArrayData<T> ArrayDataType;
|
||||
typedef std::vector<T> vector;
|
||||
typedef const std::vector<T> const_vector;
|
||||
typedef std::tr1::shared_ptr<vector> shared_vector;
|
||||
typedef PVValueArray & reference;
|
||||
typedef const PVValueArray & const_reference;
|
||||
// end deprecated
|
||||
|
||||
static const ScalarType typeCode;
|
||||
|
||||
@@ -1036,40 +1119,122 @@ public:
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~PVValueArray() {}
|
||||
|
||||
// Primative array manipulations
|
||||
|
||||
//! unchecked writable reference
|
||||
//! Before you call this directly, consider using one
|
||||
//! other the following methods.
|
||||
virtual const svector& viewUnsafe() const = 0;
|
||||
|
||||
//! Exchange our contents for the provided.
|
||||
//! Fails for Immutable arrays
|
||||
virtual void swap(svector& other) = 0;
|
||||
|
||||
//! Discard current contents and replaced with the provided.
|
||||
//! Fails for Immutable arrays
|
||||
virtual void replace(const svector& next)
|
||||
{
|
||||
svector temp(next);
|
||||
this->swap(temp);
|
||||
}
|
||||
|
||||
// Derived operations
|
||||
|
||||
//! Fetch a read-only view of the current array data
|
||||
inline const_svector view() const
|
||||
{
|
||||
const_svector newref(this->viewUnsafe());
|
||||
return newref;
|
||||
}
|
||||
|
||||
//! Remove and return the current array data
|
||||
inline svector take()
|
||||
{
|
||||
svector result;
|
||||
this->swap(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
//! take() with an implied make_unique()
|
||||
inline svector reuse()
|
||||
{
|
||||
svector result;
|
||||
this->swap(result);
|
||||
result.make_unique();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array elements
|
||||
* @param offset The offset of the first element,
|
||||
* @param length The number of elements to get.
|
||||
* @param data The place where the data is placed.
|
||||
*/
|
||||
virtual std::size_t get(
|
||||
std::size_t offset, std::size_t length, ArrayDataType &data) = 0;
|
||||
std::size_t get(
|
||||
std::size_t offset, std::size_t length, ArrayDataType &data) USAGE_DEPRECATED
|
||||
{
|
||||
const_svector ref = this->view();
|
||||
ref.slice(offset, length);
|
||||
data.data.resize(ref.size());
|
||||
data.offset = 0;
|
||||
std::copy(ref.begin(), ref.end(), data.data.begin());
|
||||
return ref.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Put data into the array.
|
||||
* Copy data into the array growing the length as needed.
|
||||
* @param offset The offset of the first element,
|
||||
* @param length The number of elements to get.
|
||||
* @param from The new values to put into the array.
|
||||
* @param fromOffset The offset in from.
|
||||
* @return The number of elements put into the array.
|
||||
*/
|
||||
virtual std::size_t put(std::size_t offset,
|
||||
std::size_t length, const_pointer from, std::size_t fromOffset) = 0;
|
||||
virtual std::size_t put(std::size_t offset,
|
||||
std::size_t length, const_vector &from, std::size_t fromOffset);
|
||||
std::size_t put(std::size_t offset,
|
||||
std::size_t length, const_pointer from, std::size_t fromOffset) USAGE_DEPRECATED
|
||||
{
|
||||
from += fromOffset;
|
||||
|
||||
svector temp;
|
||||
this->swap(temp);
|
||||
if(temp.size() < length+offset)
|
||||
temp.resize(length+offset);
|
||||
else
|
||||
temp.make_unique();
|
||||
|
||||
std::copy(from, from + length, temp.begin() + offset);
|
||||
this->swap(temp);
|
||||
return length;
|
||||
}
|
||||
|
||||
std::size_t put(std::size_t offset,
|
||||
std::size_t length, const_vector &from, std::size_t fromOffset) USAGE_DEPRECATED
|
||||
{ return this->put(offset,length, &from[0], fromOffset); }
|
||||
|
||||
/**
|
||||
* Share data from another source.
|
||||
* @param value The data to share.
|
||||
* @param capacity The capacity of the array.
|
||||
* @param length The length of the array.
|
||||
*/
|
||||
virtual void shareData(
|
||||
void shareData(
|
||||
shared_vector const & value,
|
||||
std::size_t capacity,
|
||||
std::size_t length) = 0;
|
||||
virtual pointer get() = 0;
|
||||
virtual pointer get() const = 0;
|
||||
virtual vector const & getVector() = 0;
|
||||
virtual shared_vector const & getSharedVector() = 0;
|
||||
std::size_t length) USAGE_DEPRECATED
|
||||
{
|
||||
vector& vref = *value.get();
|
||||
typename svector::shared_pointer_type p(&vref[0],
|
||||
detail::shared_ptr_vector_deletor<T>(value));
|
||||
svector temp(p, 0, std::min(length, vref.size()));
|
||||
this->swap(temp);
|
||||
}
|
||||
|
||||
pointer get() const {
|
||||
return this->viewUnsafe().data();
|
||||
}
|
||||
|
||||
vector const & getVector() USAGE_ERROR("No longer implemented");
|
||||
shared_vector const & getSharedVector() USAGE_ERROR("No longer implemented");
|
||||
|
||||
std::ostream& dumpValue(std::ostream& o) const
|
||||
{
|
||||
@@ -1092,30 +1257,67 @@ public:
|
||||
return o << *(get() + index);
|
||||
}
|
||||
|
||||
virtual void getAs(ScalarType dtype, void* ptr, size_t count, size_t offset) const
|
||||
virtual void
|
||||
getAs(ScalarType id, ::epics::pvData::shared_vector<void>& out) const
|
||||
{
|
||||
castUnsafeV(count, dtype, ptr, typeCode, (const void*)(get()+offset));
|
||||
const svector& data(viewUnsafe());
|
||||
::epics::pvData::shared_vector<void> temp(static_shared_vector_cast<void>(data));
|
||||
if(id==typeCode) {
|
||||
out = temp; // no convert = no copy
|
||||
} else {
|
||||
//TODO: reuse out if possible??
|
||||
::epics::pvData::shared_vector<void> vcopy(ScalarTypeFunc::allocArray(id, data.size()));
|
||||
|
||||
castUnsafeV(data.size(), id, vcopy.data(), typeCode, temp.data());
|
||||
|
||||
out.swap(vcopy);
|
||||
}
|
||||
}
|
||||
virtual void putFrom(ScalarType dtype, const void*ptr, size_t count, size_t offset)
|
||||
|
||||
virtual size_t copyOut(ScalarType id, void* ptr, size_t olen) const
|
||||
{
|
||||
if(getLength()<offset+count)
|
||||
setLength(offset+count);
|
||||
castUnsafeV(count, typeCode, (void*)(get()+offset), dtype, ptr);
|
||||
const svector& data(viewUnsafe());
|
||||
size_t len = std::min(olen, data.size());
|
||||
|
||||
castUnsafeV(len, id, ptr, typeCode, (const void*)data.data());
|
||||
return len;
|
||||
}
|
||||
|
||||
virtual void
|
||||
putFrom(ScalarType id, const ::epics::pvData::shared_vector<void>& inp)
|
||||
{
|
||||
if(id==typeCode) {
|
||||
svector next(static_shared_vector_cast<T>(inp));
|
||||
this->swap(next); // no convert == no copy
|
||||
} else {
|
||||
size_t len = inp.size() / ScalarTypeFunc::elementSize(id);
|
||||
svector result;
|
||||
this->swap(result);
|
||||
result.resize(len);
|
||||
|
||||
castUnsafeV(len, typeCode, result.data(), id, inp.data());
|
||||
|
||||
this->swap(result);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void copyIn(ScalarType id, const void* ptr, size_t len)
|
||||
{
|
||||
svector data;
|
||||
this->swap(data);
|
||||
data.resize(len);
|
||||
castUnsafeV(len, typeCode, (void*)data.data(), id, ptr);
|
||||
this->swap(data);
|
||||
}
|
||||
|
||||
virtual void assign(PVScalarArray& pv)
|
||||
{
|
||||
if(this==&pv)
|
||||
return;
|
||||
if(isImmutable())
|
||||
throw std::invalid_argument("Destination is immutable");
|
||||
if(pv.isImmutable() && typeCode==pv.getScalarArray()->getElementType()) {
|
||||
PVValueArray& pvr = static_cast<PVValueArray&>(pv);
|
||||
shareData(pvr.getSharedVector(), pvr.getCapacity(), pvr.getLength());
|
||||
} else {
|
||||
setLength(pv.getLength());
|
||||
pv.getAs(typeCode, (void*)get(), std::min(getLength(),pv.getLength()), 0);
|
||||
}
|
||||
::epics::pvData::shared_vector<void> temp;
|
||||
pv.getAs(typeCode, temp);
|
||||
svector next(static_shared_vector_cast<T>(temp));
|
||||
this->swap(next);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -1124,13 +1326,6 @@ protected:
|
||||
friend class PVDataCreate;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::size_t PVValueArray<T>::put(
|
||||
std::size_t offset,
|
||||
std::size_t length,
|
||||
const_vector &from,
|
||||
std::size_t fromOffset)
|
||||
{ return put(offset,length, &from[0], fromOffset); }
|
||||
|
||||
/**
|
||||
* Definitions for the various scalarArray types.
|
||||
@@ -1281,6 +1476,9 @@ private:
|
||||
*/
|
||||
|
||||
extern PVDataCreatePtr getPVDataCreate();
|
||||
|
||||
|
||||
#undef USAGE_DEPRECATED
|
||||
#undef USAGE_ERROR
|
||||
|
||||
}}
|
||||
#endif /* PVDATA_H */
|
||||
|
||||
Reference in New Issue
Block a user