add serializeToVector

This commit is contained in:
Michael Davidsaver
2015-11-23 15:19:06 -05:00
parent 45427d3202
commit 85a1a48b00
3 changed files with 163 additions and 2 deletions

View File

@@ -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.

View File

@@ -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);
}
}
}

View File

@@ -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;