add serializeToVector
This commit is contained in:
@@ -10,6 +10,8 @@
|
||||
#ifndef SERIALIZE_H
|
||||
#define SERIALIZE_H
|
||||
|
||||
#include <epicsTypes.h>
|
||||
|
||||
#include <pv/byteBuffer.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
@@ -150,6 +152,17 @@ namespace epics { namespace pvData {
|
||||
DeserializableControl *flusher) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Push serialize and append to the provided byte vector.
|
||||
* No caching is done. Only complete serialization.
|
||||
*
|
||||
* @param S A Serializable object
|
||||
* @param byteOrder Byte order to write (EPICS_ENDIAN_LITTLE or EPICS_ENDIAN_BIG)
|
||||
* @param out The output vector. Results are appended
|
||||
*/
|
||||
void serializeToVector(const Serializable *S,
|
||||
int byteOrder,
|
||||
std::vector<epicsUInt8>& out);
|
||||
|
||||
/**
|
||||
* @brief Class for serializing bitSets.
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/byteBuffer.h>
|
||||
#include <pv/epicsException.h>
|
||||
#include <pv/byteBuffer.h>
|
||||
#include <pv/serializeHelper.h>
|
||||
@@ -139,6 +140,78 @@ namespace epics {
|
||||
else
|
||||
return emptyStringtring;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
using namespace epics::pvData;
|
||||
|
||||
struct ToString : public epics::pvData::SerializableControl
|
||||
{
|
||||
typedef std::vector<epicsUInt8> buf_type;
|
||||
buf_type buf;
|
||||
buf_type& out;
|
||||
ByteBuffer bufwrap;
|
||||
|
||||
ToString(buf_type& out, int byteOrder = EPICS_BYTE_ORDER)
|
||||
:buf(16*1024)
|
||||
,out(out)
|
||||
,bufwrap((char*)&buf[0], buf.size(), byteOrder)
|
||||
{}
|
||||
|
||||
virtual void flushSerializeBuffer()
|
||||
{
|
||||
size_t N = out.size();
|
||||
out.resize(out.size()+bufwrap.getPosition());
|
||||
std::copy(buf.begin(),
|
||||
buf.begin()+bufwrap.getPosition(),
|
||||
out.begin()+N);
|
||||
bufwrap.clear();
|
||||
}
|
||||
|
||||
virtual void ensureBuffer(std::size_t size)
|
||||
{
|
||||
flushSerializeBuffer();
|
||||
assert(bufwrap.getRemaining()>0);
|
||||
}
|
||||
|
||||
virtual void alignBuffer(std::size_t alignment)
|
||||
{
|
||||
if(bufwrap.getRemaining()<alignment)
|
||||
flushSerializeBuffer();
|
||||
assert(bufwrap.getRemaining()>=alignment);
|
||||
bufwrap.align(alignment);
|
||||
}
|
||||
|
||||
virtual bool directSerialize(
|
||||
ByteBuffer *existingBuffer,
|
||||
const char* toSerialize,
|
||||
std::size_t elementCount,
|
||||
std::size_t elementSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void cachedSerialize(
|
||||
std::tr1::shared_ptr<const Field> const & field,
|
||||
ByteBuffer* buffer)
|
||||
{
|
||||
field->serialize(buffer, this);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace epics {
|
||||
namespace pvData {
|
||||
void serializeToVector(const Serializable *S,
|
||||
int byteOrder,
|
||||
std::vector<epicsUInt8>& out)
|
||||
{
|
||||
ToString TS(out, byteOrder);
|
||||
S->serialize(&TS.bufwrap, &TS);
|
||||
TS.flushSerializeBuffer();
|
||||
assert(TS.bufwrap.getPosition()==0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <fstream>
|
||||
|
||||
#include <epicsUnitTest.h>
|
||||
#include <epicsTypes.h>
|
||||
#include <testMain.h>
|
||||
#include <dbDefs.h> // for NELEMENTS
|
||||
|
||||
@@ -761,11 +762,83 @@ void testStringCopy() {
|
||||
testDiag("implementation of string assignment operator does not share content");
|
||||
}
|
||||
|
||||
static
|
||||
void printbytes(size_t N, const epicsUInt8 *buf)
|
||||
{
|
||||
bool needeol = false;
|
||||
for(size_t i=0; i<N; i++)
|
||||
{
|
||||
if(i%16==0) {
|
||||
printf("# %04x ", (unsigned)i);
|
||||
needeol = true;
|
||||
}
|
||||
printf("%02x", buf[i]);
|
||||
if(i%16==15) {
|
||||
printf("\n");
|
||||
needeol = false;
|
||||
} else if(i%4==3) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
if(needeol)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static
|
||||
const char expected_le[] = "\x2a\000\000\000\x07testing";
|
||||
|
||||
static
|
||||
const char expected_be[] = "\000\000\000\x2a\x07testing";
|
||||
|
||||
static
|
||||
void testToString(int byteOrder)
|
||||
{
|
||||
testDiag("testToString(%d)", byteOrder);
|
||||
|
||||
StructureConstPtr _type = getFieldCreate()->createFieldBuilder()
|
||||
->add("X", pvInt)->add("Y", pvString)
|
||||
->createStructure();
|
||||
|
||||
PVStructurePtr _data = getPVDataCreate()->createPVStructure(_type);
|
||||
|
||||
_data->getSubFieldT<PVInt>("X")->put(42);
|
||||
_data->getSubFieldT<PVString>("Y")->put("testing");
|
||||
|
||||
std::vector<epicsUInt8> bytes;
|
||||
serializeToVector(_data.get(), byteOrder, bytes);
|
||||
|
||||
const char *expected;
|
||||
size_t count;
|
||||
if(byteOrder==EPICS_ENDIAN_LITTLE) {
|
||||
expected = expected_le;
|
||||
count = NELEMENTS(expected_le)-1;
|
||||
} else if(byteOrder==EPICS_ENDIAN_BIG) {
|
||||
expected = expected_be;
|
||||
count = NELEMENTS(expected_be)-1;
|
||||
} else {
|
||||
throw std::logic_error("Unsupported mixed endian");
|
||||
}
|
||||
|
||||
testOk(bytes.size()==count,
|
||||
"%u == %u", (unsigned)bytes.size(),
|
||||
(unsigned)count);
|
||||
|
||||
size_t N = std::min(bytes.size(), count);
|
||||
|
||||
testOk(memcmp(&bytes[0], expected, N)==0, "Match [0,%u)", (unsigned)N);
|
||||
|
||||
testDiag("Expected (%u)", (unsigned)bytes.size());
|
||||
printbytes(count, (epicsUInt8*)expected);
|
||||
|
||||
testDiag("Actual (%u)", (unsigned)count);
|
||||
printbytes(bytes.size(), &bytes[0]);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
MAIN(testSerialization) {
|
||||
|
||||
testPlan(226);
|
||||
testPlan(230);
|
||||
|
||||
flusher = new SerializableControlImpl();
|
||||
control = new DeserializableControlImpl();
|
||||
@@ -787,6 +860,8 @@ MAIN(testSerialization) {
|
||||
testArraySizeType();
|
||||
testBoundedString();
|
||||
|
||||
testToString(EPICS_ENDIAN_BIG);
|
||||
testToString(EPICS_ENDIAN_LITTLE);
|
||||
|
||||
delete buffer;
|
||||
delete control;
|
||||
|
||||
Reference in New Issue
Block a user