I have an school assignment where we are asked to write our own serialize and deserialize functions in c++.
Consider this simple class
class Hello {
int Int32;
float Float;
vector<int> Array;
};
I am not able to find any way do it. Can anybody just give me rough guidance of how to achieve this?
>Solution :
I’ve put together an outline of what it could look like.
- I’ve made a class called
LEB128that you can initialize with an integer type. - You’ll have to implement the
LEB128encoding/decoding. - I’ve commented in the code to explain what it’s doing.
#include <iostream>
#include <type_traits>
#include <vector>
class LEB128 {
public:
LEB128() = default;
// a constructor taking an integer and LEB128 encodes it
// by putting the encoded data in the `data` member variable:
template<class T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
LEB128(T v) {
if constexpr (std::is_signed_v<T>) {
// implement signed LEB128 here, put data in `data`
} else {
// implement unsigned LEB128 here,put data in `data`
}
}
// add one LEB128 object to this object:
LEB128& operator+=(const LEB128& rhs) {
data.insert(data.end(), rhs.data.begin(), rhs.data.end());
return *this;
}
// decode the LEB128 encoded data and return it as `T`
template<class T>
T to() const {
// implement decoding the LEB128 encoded data in `data` and return it as
// type T
return T{};
}
// write a LEB128 to a stream
friend std::ostream& operator<<(std::ostream& os, const LEB128& l) {
return os.write(reinterpret_cast<const char*>(l.data.data()), l.data.size());
}
// read a LEB128 from a stream
friend std::istream& operator>>(std::istream& is, LEB128& l) {
l.data.clear();
// implement reading LEB128 bytes here and put them in `l.data`
return is;
}
private:
std::vector<uint8_t> data;
};
// concatenate two LEB128's
LEB128 operator+(const LEB128& lhs, const LEB128& rhs) {
LEB128 rv(lhs);
rv += rhs;
return rv;
}
class Hello {
int32_t Int32;
float Float;
std::vector<uint8_t> U8Array;
// serialize a Hello:
friend std::ostream& operator<<(std::ostream& os, const Hello& h) {
// figure out what to do with the `float` - this serializes the integers:
LEB128 leb = LEB128(h.Int32) + LEB128(h.U8Array.size());
for(auto val : h.U8Array) leb += LEB128(val);
return os << leb;
}
// deserialize a Hello:
friend std::istream& operator>>(std::istream& is, Hello& l) {
LEB128 lebInt32, lebSize;
if(is >> lebInt32 >> lebSize) {
l.Int32 = lebInt32.to<int32_t>();
size_t size = lebSize.to<size_t>();
l.U8Array.resize(size);
LEB128 tmp;
for(auto& val : l.U8Array) {
is >> tmp;
val = tmp.to<uint8_t>();
}
}
return is;
}
};
Now serializing a Hello could be done like this:
Hello h;
std::ofstream file("Hello.bin");
file << h;
and deserializing:
Hello h;
std::ifstream file("Hello.bin");
file >> h;