Merge pull request #17 from mdavidsaver/sertovector

add serializeToVector()
This commit is contained in:
dhickin
2016-02-10 14:04:01 +00:00
3 changed files with 267 additions and 2 deletions
+37
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,41 @@ 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 deserializeFromBuffer Deserialize into S from provided vector
* @param S A Serializeable object. The current contents will be replaced
* @param in The input buffer (byte order of this buffer is used)
* @throws std::logic_error if input buffer is too small. State of S is then undefined.
*/
void deserializeFromBuffer(Serializable *S,
ByteBuffer& in);
/**
* @brief deserializeFromBuffer Deserialize into S from provided vector
* @param S A Serializeable object. The current contents will be replaced
* @param byteOrder Byte order to write (EPICS_ENDIAN_LITTLE or EPICS_ENDIAN_BIG)
* @param in The input vector
* @throws std::logic_error if input buffer is too small. State of S is then undefined.
*/
inline void deserializeFromVector(Serializable *S,
int byteOrder,
const std::vector<epicsUInt8>& in)
{
ByteBuffer B((char*)&in[0], in.size(), byteOrder); // we promise not the modify 'in'
deserializeFromBuffer(S, B);
}
/**
* @brief Class for serializing bitSets.
+128 -1
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,132 @@ 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);
}
}
}
namespace {
struct FromString : public epics::pvData::DeserializableControl
{
ByteBuffer &buf;
epics::pvData::FieldCreatePtr create;
FromString(ByteBuffer& b)
:buf(b)
,create(epics::pvData::getFieldCreate())
{}
virtual void ensureData(std::size_t size)
{
if(size>buf.getRemaining())
throw std::logic_error("Incomplete buffer");
}
virtual void alignData(std::size_t alignment)
{
size_t pos = buf.getPosition(), k = alignment-1;
if(pos&k) {
std::size_t npad = alignment-(pos&k);
ensureData(npad);
buf.align(alignment);
}
}
virtual bool directDeserialize(
ByteBuffer *existingBuffer,
char* deserializeTo,
std::size_t elementCount,
std::size_t elementSize)
{
return false;
}
virtual std::tr1::shared_ptr<const Field> cachedDeserialize(
ByteBuffer* buffer)
{
return create->deserialize(buffer, this);
}
};
}
namespace epics {
namespace pvData {
void deserializeFromBuffer(Serializable *S,
ByteBuffer& buf)
{
FromString F(buf);
S->deserialize(&buf, &F);
}
}
}
+102 -1
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,107 @@ 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]);
}
void testFromString(int byteOrder)
{
testDiag("testFromString(%d)", byteOrder);
StructureConstPtr _type = getFieldCreate()->createFieldBuilder()
->add("X", pvInt)->add("Y", pvString)
->createStructure();
PVStructurePtr _data = getPVDataCreate()->createPVStructure(_type);
if(byteOrder==EPICS_ENDIAN_LITTLE) {
ByteBuffer buf((char*)expected_le, NELEMENTS(expected_le)-1, byteOrder);
deserializeFromBuffer(_data.get(), buf);
} else if(byteOrder==EPICS_ENDIAN_BIG) {
ByteBuffer buf((char*)expected_be, NELEMENTS(expected_be)-1, byteOrder);
deserializeFromBuffer(_data.get(), buf);
} else {
throw std::logic_error("Unsupported mixed endian");
}
testOk1(_data->getSubFieldT<PVInt>("X")->get()==42);
testOk1(_data->getSubFieldT<PVString>("Y")->get()=="testing");
}
} // end namespace
MAIN(testSerialization) {
testPlan(226);
testPlan(234);
flusher = new SerializableControlImpl();
control = new DeserializableControlImpl();
@@ -787,6 +884,10 @@ MAIN(testSerialization) {
testArraySizeType();
testBoundedString();
testToString(EPICS_ENDIAN_BIG);
testToString(EPICS_ENDIAN_LITTLE);
testFromString(EPICS_ENDIAN_BIG);
testFromString(EPICS_ENDIAN_LITTLE);
delete buffer;
delete control;