I am trying to Serialize a class.
Class definition:
class StartPeerSessionRequest {
public:
StartPeerSessionRequest();
virtual ~StartPeerSessionRequest();
void composeRequestwithHardCodeValues();
void save();
stringstream serializedRequest;
/*boost::serialization::binary_object serlreq;*/
private:
StartPeerSessionRequest(const StartPeerSessionRequest &);
uint16_t mProtocolVersion;
uint16_t mSessionFlags;
uint16_t mMaxResponseLength;
string mMake;
string mModel;
string mSerialNumber;
uint8_t mTrackDelay;
string mHeadUnitModel;
string mCarModelYear;
string mVin;
uint16_t mVehicleMileage;
uint8_t mShoutFormat;
uint8_t mNotificationInterval;
friend class boost::serialization::access;
template <typename Archive> void serialize(Archive &ar, const unsigned int version);
};
StartPeerSessionRequest::StartPeerSessionRequest() {
mProtocolVersion = 1 * 10000 + 14 * 100 + 4;
mSessionFlags = 1;
mMaxResponseLength = 0;
mMake = "MyMake";
mModel = "MyModel";
mSerialNumber = "10000";
mTrackDelay = 0;
mHeadUnitModel = "Headunit";
mCarModelYear = "2014";
mVin = "1234567980";
mVehicleMileage = 1000;
mShoutFormat = 3;
mNotificationInterval = 1;
}
template <class Archive> void StartPeerSessionRequest::serialize(Archive &ar, const unsigned int version) {
ar & mProtocolVersion;
ar & mSessionFlags;
ar & mMaxResponseLength;
ar & mMake;
ar & mModel;
ar & mSerialNumber;
ar & mTrackDelay;
ar & mHeadUnitModel;
ar & mCarModelYear;
ar & mVin;
ar & mVehicleMileage;
ar & mShoutFormat;
ar & mNotificationInterval;
}
void StartPeerSessionRequest::save() {
boost::archive::binary_oarchive oa(serlreq, boost::archive::no_header);
oa << (*this);
/*cout<<"\n binary_oarchive :"<<serlreq.size();*/
boost::archive::text_oarchive ota(serializedRequest, boost::archive::no_header);
ota << (*this);
cout << "\n text_oarchive :" << serializedRequest.str() << "size :" << serializedRequest.str().size();
}
serializedRequest.str.size()
provides me a length of 87
Actually it should provide me 65 bytes. (I've counted u can figure that out from the constructor)
I suspect it is appending lengths in between.
I have tried using text_archive
also it doesnt work.
What I need is to just plain serialize class members as it is.
I guess i need to use some traits or wrappers.
Please let me know
Thanks
Okay, so, just to see how I'd do, I've tried to reach the optimum sizes I calculated on the back of my napkin:
I can see how you'd expect 57, 63, or 75 bytes
mProtocolVersion = 1*10000+14*100+4; // 2 bytes mSessionFlags = 1; // 2 bytes mMaxResponseLength = 0; // 2 bytes mMake = "MyMake"; // 6 bytes + length mModel = "MyModel"; // 7 bytes + length mSerialNumber = "10000"; // 5 bytes + length mTrackDelay = 0; // 1 byte mHeadUnitModel = "Headunit"; // 8 bytes + length mCarModelYear = "2014"; // 4 bytes + length mVin = "1234567980"; // 10 bytes + length mVehicleMileage = 1000; // 2 byte mShoutFormat = 3; // 1 byte mNotificationInterval = 1; // 1 byte // -------------------------------------- // 51 bytes + 6 x length
In this instance, I created binary serialization code using Boost Spirit (Karma for serialization and Qi for de-serialization). I made the size of the length field configurable (8,16,32 or 64 bit unsigned).
Here's a working proof of concept: Live On Coliru
generate()
The const generate member function delegates the work to helper functions in a separate namespace:
template <typename Container>
bool generate(Container& bytes) const {
auto out = std::back_inserter(bytes);
using my_serialization_helpers::do_generate;
return do_generate(out, mProtocolVersion)
&& do_generate(out, mSessionFlags)
&& do_generate(out, mMaxResponseLength)
&& do_generate(out, mMake)
&& do_generate(out, mModel)
&& do_generate(out, mSerialNumber)
&& do_generate(out, mTrackDelay)
&& do_generate(out, mHeadUnitModel)
&& do_generate(out, mCarModelYear)
&& do_generate(out, mVin)
&& do_generate(out, mVehicleMileage)
&& do_generate(out, mShoutFormat)
&& do_generate(out, mNotificationInterval);
}
Note that
do_generate
overloads can be freely added as required for future typesstd::vector<unsigned char>
, to e.g. boost::interprocess::containers::string<char, char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> >
.parse()
The parse method is very similar except it delegates to do_parse
overloads to do the work.
The test program roundtrips with all possible configurations:
As you can see it's not even that outrageous that the natural Boost Serialization solution would take 107 bytes on my system (it's only 8 bytes more than my last configuration).
Note also, that since the Karma generators all take any output iterator, it should be relatively easy to wire it directly into the low-level Boost Archive operations for performance and to avoid allocating intermediate storage.