Skip to content

Instantly share code, notes, and snippets.

@motonacciu
Last active December 17, 2015 11:39
Show Gist options
  • Select an option

  • Save motonacciu/5603530 to your computer and use it in GitHub Desktop.

Select an option

Save motonacciu/5603530 to your computer and use it in GitHub Desktop.
namespace detail {
template <class T>
struct deserialize_helper;
template <class T>
struct deserialize_helper {
/**
* Deserialization for integral types and POD data types.
*
* This is done by simply relying on the sizeof() operator of the object.
* It is important that the datatype we are deserializing has a default
* contructor, otherwise you need to provide a specialization for that type
*/
static T apply(StreamType::const_iterator& begin, StreamType::const_iterator end) {
assert(begin+sizeof(T)<=end && "Error: not enough bytes to deserialize type");
T val;
uint8_t* ptr = reinterpret_cast<uint8_t*>(&val);
std::copy(begin, begin+sizeof(T), ptr);
begin+=sizeof(T);
return val;
}
};
template <class T>
struct deserialize_helper<std::vector<T>> {
/**
* Deserialization for vector types.
*
* We read the first size_t value which contains the number of elements
* and then recursively read each of them. An optimization can be done
* for which we avoid recursion in the case we have a vector of PODs or
* integral type (soon to come)
*/
static std::vector<T> apply(StreamType::const_iterator& begin,
StreamType::const_iterator end)
{
// retrieve the number of elements
size_t size = deserialize_helper<size_t>::apply(begin,end);
std::vector<T> vect(size);
for(size_t i=0; i<size; ++i) {
/**
* Call the move-copy constructor so that the additional copy
* is avoided
*/
vect[i] = std::move(deserialize_helper<T>::apply(begin,end));
}
return vect;
}
};
template <>
struct deserialize_helper<std::string> {
/**
* Deserialization for strings.
*
* similar to vectors but we can avoid recursion since the elements
* of a string are always bytes.
*/
static std::string apply(StreamType::const_iterator& begin,
StreamType::const_iterator end)
{
// retrieve the number of elements
size_t size = deserialize_helper<size_t>::apply(begin,end);
// We need to consider the case of empty strings separately
if (size == 0u) return std::string();
std::string str(size,'\0');
for(size_t i=0; i<size; ++i) {
str.at(i) = deserialize_helper<uint8_t>::apply(begin,end);
}
return str;
}
};
template <class tuple_type>
inline void deserialize_tuple(tuple_type& obj, StreamType::const_iterator& begin,
StreamType::const_iterator end, int_<0>) {
constexpr size_t idx = std::tuple_size<tuple_type>::value-1;
typedef typename std::tuple_element<idx,tuple_type>::type T;
// Use std::move() to force R-value copy constructor and avoid the copy
std::get<idx>(obj) = std::move(deserialize_helper<T>::apply(begin, end));
}
template <class tuple_type, size_t pos>
inline void deserialize_tuple(tuple_type& obj, StreamType::const_iterator& begin,
StreamType::const_iterator end, int_<pos>) {
constexpr size_t idx = std::tuple_size<tuple_type>::value-pos-1;
typedef typename std::tuple_element<idx,tuple_type>::type T;
// Use std::move() to force R-value copy constructor and avoid the copy
std::get<idx>(obj) = std::move(deserialize_helper<T>::apply(begin, end));
// meta-recur
deserialize_tuple(obj, begin, end, int_<pos-1>());
}
template <class... T>
struct deserialize_helper<std::tuple<T...>> {
/**
* Deserialization for tuples
*
* same pattern as for serialization
*/
static std::tuple<T...> apply(StreamType::const_iterator& begin,StreamType::const_iterator end)
{
// if only this worked... sigh!
// return std::make_tuple(deserialize_helper<T>::apply(begin,end)...);
std::tuple<T...> ret;
deserialize_tuple(ret, begin, end, int_<sizeof...(T)-1>());
return ret;
}
};
} // end detail namespace
template <class T>
inline T deserialize(StreamType::const_iterator& begin, const StreamType::const_iterator& end) {
return detail::deserialize_helper<T>::apply(begin, end);
}
template <class T>
inline T deserialize(const StreamType& res) {
StreamType::const_iterator it = res.cbegin();
return deserialize(it, res.cend());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment