I am reading other's code and there is a serialization version of this class:
struct ObjectInfo
{
int32_t m_typeId;
string m_objectName;
vector<int32_t> m_haveKeysId;
map<int32_t,double> m_objectFeatures;
ObjectInfo():m_typeId(-1),m_objectName("")
{
m_objectFeatures.clear();
m_haveKeysId.clear();
}
}
The binary version of it is the following:
struct ObjectInfo_B
{
int32_t m_typeId;
int32_t m_objectNamePos;
int32_t m_startIndex;
int32_t m_endIndex;
int32_t m_haveKeysIdStartIndex;
int32_t m_haveKeysIdEndIndex;
ObjectInfo_B()
{
m_typeId = -1;
m_objectNamePos = 0;
m_startIndex = -1;
m_endIndex = -1;
m_haveKeysIdStartIndex = -1;
m_haveKeysIdEndIndex = -1;
}
Then there is a vector of ObjectInfo:
vector<ObjectInfo> *objectsVec;
ObjectInfo_B *bObjects;
...
Now the code to convert is like below:
startIndex = 0;
int32_t curBufferSize = 0;
for(size_t i = 0;i<objectsVec->size();i )
{
bObjects[i].m_typeId = (*objectsVec)[i].m_typeId;
bObjects[i].m_objectNamePos = curBufferSize;
strcpy(m_objectNameBuffer curBufferSize,(*objectsVec)[i].m_objectName.c_str());
curBufferSize = (*objectsVec)[i].m_objectName.size() 1;
bObjects[i].m_startIndex = startIndex;
bObjects[i].m_endIndex = startIndex (*objectsVec)[i].m_objectFeatures.size();
startIndex = bObjects[i].m_endIndex;
bObjects[i].m_haveKeysIdStartIndex = haveKeyStartIndex;
bObjects[i].m_haveKeysIdEndIndex = haveKeyStartIndex (*objectsVec)[i].m_haveKeysId.size();
...
fwrite((char*)bObjects,sizeof(ObjectInfo_B),wcount,output);
This seems to be very complicated, and I am not farmilaria with serialization. Is there an easier way to do it in C ? A quick search indicates that this below can do similar things, but can it do the conversion for the above code in a much simpler way?
https://www.boost.org/doc/libs/1_37_0/libs/serialization/doc/index.html
CodePudding user response:
The main question is why you want to hold two different versions of the same class. If the main purpose of the binary version is providing a binary I/O, I'd recommend writing a corresponding I/O function. Here's a simple example.
If you are dealing with legacy code, a constructor of ObjectInfo_b from ObjectInfo makes the code more readable:
ObjectInfo_b(const ObjectInfo& obj) {
// copy all member variables according to your code snippet
m_typeId = obj.m_typeId;
// ...
}
Then the serialization part looks like this
vector<ObjectInfo> objectsVec; // Note: removed pointer
vector<ObjectInfo_b> bObjects; // also using a std::vector
for (const ObjectInfo obj : objectsVec) {
// create ObjectInfo_b from obj and append to vector via move semantics
bObjects.emplace_back(ObjectInfo_b(obj));
}
// ...
// Pointer to objects
bObjects* bObject_ptr = &bObjects[0];
Again, with the provided information, the class seems duplicate and should be removed. A function that writes ObjectInfo in a binary format is sufficient.
CodePudding user response:
A sketch of the direction I would take to refactor the code:
#include <cstdint>
#include <iostream>
#include <fstream>
#include <bitcast>
struct B
{
};
struct ObjectInfo_B
{
std::int32_t m_typeId = -1;
std::int32_t m_objectNamePos = -1;
std::int32_t m_startIndex = -1;
std::int32_t m_endIndex = -1;
std::int32_t m_haveKeysIdStartIndex = -1;
std::int32_t m_haveKeysIdEndIndex = -1;
};
auto get_data_from_objects(const std::vector<B>& objects)
{
std::int32_t startIndex{0};
std::int32_t curBufferSize{0};
std::vector<ObjectInfo_B> object_infos(objects.size());
for (std::size_t n = 0; n < object.size(); n )
{
auto& object_info = objects_info[n];
auto& object = objects[n];
object_info.m_typeId = object.m_typeId;
object_info.m_objectNamePos = curBufferSize;
....
}
}
std::ostream operator<<(std::ostream& os, const std::vector<ObjectInfo_B>& object_infos)
{
for(const ObjectInfo_B& object_info : object_infos)
{
os.fwrite(std::bitcast<char*>(&object_info), sizeof(ObjectInfo_B));
}
}
void save_to(std::ostream& os, const std::vector<B>& objects)
{
auto object_infos = get_data_from_objects(objects);
os << object_infos();
}