Home > Back-end >  Is there a better way to do object serialization for this class?
Is there a better way to do object serialization for this class?

Time:12-09

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();
}
  • Related